diff options
Diffstat (limited to 'third_party/libwebrtc/webrtc/modules/rtp_rtcp')
224 files changed, 74751 insertions, 0 deletions
diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/BUILD.gn b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/BUILD.gn new file mode 100644 index 0000000000..c04411609e --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/BUILD.gn @@ -0,0 +1,422 @@ +# 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. + +import("../../webrtc.gni") + +rtc_source_set("rtp_rtcp_format") { + public = [ + "include/rtp_cvo.h", + "include/rtp_header_extension_map.h", + "include/rtp_rtcp_defines.h", + "source/byte_io.h", + "source/rtcp_packet.h", + "source/rtcp_packet/app.h", + "source/rtcp_packet/bye.h", + "source/rtcp_packet/common_header.h", + "source/rtcp_packet/compound_packet.h", + "source/rtcp_packet/dlrr.h", + "source/rtcp_packet/extended_jitter_report.h", + "source/rtcp_packet/extended_reports.h", + "source/rtcp_packet/fir.h", + "source/rtcp_packet/nack.h", + "source/rtcp_packet/pli.h", + "source/rtcp_packet/psfb.h", + "source/rtcp_packet/rapid_resync_request.h", + "source/rtcp_packet/receiver_report.h", + "source/rtcp_packet/remb.h", + "source/rtcp_packet/report_block.h", + "source/rtcp_packet/rrtr.h", + "source/rtcp_packet/rtpfb.h", + "source/rtcp_packet/sdes.h", + "source/rtcp_packet/sender_report.h", + "source/rtcp_packet/target_bitrate.h", + "source/rtcp_packet/tmmb_item.h", + "source/rtcp_packet/tmmbn.h", + "source/rtcp_packet/tmmbr.h", + "source/rtcp_packet/transport_feedback.h", + "source/rtcp_packet/voip_metric.h", + "source/rtp_header_extensions.h", + "source/rtp_packet.h", + "source/rtp_packet_received.h", + "source/rtp_packet_to_send.h", + ] + sources = [ + "include/rtp_rtcp_defines.cc", + "source/rtcp_packet.cc", + "source/rtcp_packet/app.cc", + "source/rtcp_packet/bye.cc", + "source/rtcp_packet/common_header.cc", + "source/rtcp_packet/compound_packet.cc", + "source/rtcp_packet/dlrr.cc", + "source/rtcp_packet/extended_jitter_report.cc", + "source/rtcp_packet/extended_reports.cc", + "source/rtcp_packet/fir.cc", + "source/rtcp_packet/nack.cc", + "source/rtcp_packet/pli.cc", + "source/rtcp_packet/psfb.cc", + "source/rtcp_packet/rapid_resync_request.cc", + "source/rtcp_packet/receiver_report.cc", + "source/rtcp_packet/remb.cc", + "source/rtcp_packet/report_block.cc", + "source/rtcp_packet/rrtr.cc", + "source/rtcp_packet/rtpfb.cc", + "source/rtcp_packet/sdes.cc", + "source/rtcp_packet/sender_report.cc", + "source/rtcp_packet/target_bitrate.cc", + "source/rtcp_packet/tmmb_item.cc", + "source/rtcp_packet/tmmbn.cc", + "source/rtcp_packet/tmmbr.cc", + "source/rtcp_packet/transport_feedback.cc", + "source/rtcp_packet/voip_metric.cc", + "source/rtp_header_extension_map.cc", + "source/rtp_header_extensions.cc", + "source/rtp_packet.cc", + "source/rtp_packet_received.cc", + ] + + deps = [ + "..:module_api", + "../..:webrtc_common", + "../../api:array_view", + "../../api:optional", + "../../api/audio_codecs:audio_codecs_api", + "../../common_video", + "../../rtc_base:rtc_base_approved", + "../../system_wrappers", + ] + + if (!build_with_mozilla) { + deps += [ "../../api:libjingle_peerconnection_api" ] + } +} + +rtc_static_library("rtp_rtcp") { + sources = [ + "include/flexfec_receiver.h", + "include/flexfec_sender.h", + "include/receive_statistics.h", + "include/remote_ntp_time_estimator.h", + "include/rtp_header_parser.h", + "include/rtp_payload_registry.h", + "include/rtp_receiver.h", + "include/rtp_rtcp.h", + "include/ulpfec_receiver.h", + "source/dtmf_queue.cc", + "source/dtmf_queue.h", + "source/fec_private_tables_bursty.h", + "source/fec_private_tables_random.h", + "source/flexfec_header_reader_writer.cc", + "source/flexfec_header_reader_writer.h", + "source/flexfec_receiver.cc", + "source/flexfec_sender.cc", + "source/forward_error_correction.cc", + "source/forward_error_correction.h", + "source/forward_error_correction_internal.cc", + "source/forward_error_correction_internal.h", + "source/packet_loss_stats.cc", + "source/packet_loss_stats.h", + "source/playout_delay_oracle.cc", + "source/playout_delay_oracle.h", + "source/receive_statistics_impl.cc", + "source/receive_statistics_impl.h", + "source/remote_ntp_time_estimator.cc", + "source/rtcp_nack_stats.cc", + "source/rtcp_nack_stats.h", + "source/rtcp_receiver.cc", + "source/rtcp_receiver.h", + "source/rtcp_sender.cc", + "source/rtcp_sender.h", + "source/rtp_format.cc", + "source/rtp_format.h", + "source/rtp_format_h264.cc", + "source/rtp_format_h264.h", + "source/rtp_format_video_generic.cc", + "source/rtp_format_video_generic.h", + "source/rtp_format_vp8.cc", + "source/rtp_format_vp8.h", + "source/rtp_format_vp9.cc", + "source/rtp_format_vp9.h", + "source/rtp_header_parser.cc", + "source/rtp_packet_history.cc", + "source/rtp_packet_history.h", + "source/rtp_payload_registry.cc", + "source/rtp_receiver_audio.cc", + "source/rtp_receiver_audio.h", + "source/rtp_receiver_impl.cc", + "source/rtp_receiver_impl.h", + "source/rtp_receiver_strategy.cc", + "source/rtp_receiver_strategy.h", + "source/rtp_receiver_video.cc", + "source/rtp_receiver_video.h", + "source/rtp_rtcp_config.h", + "source/rtp_rtcp_impl.cc", + "source/rtp_rtcp_impl.h", + "source/rtp_sender.cc", + "source/rtp_sender.h", + "source/rtp_sender_audio.cc", + "source/rtp_sender_audio.h", + "source/rtp_sender_video.cc", + "source/rtp_sender_video.h", + "source/rtp_utility.cc", + "source/rtp_utility.h", + "source/time_util.cc", + "source/time_util.h", + "source/tmmbr_help.cc", + "source/tmmbr_help.h", + "source/ulpfec_generator.cc", + "source/ulpfec_generator.h", + "source/ulpfec_header_reader_writer.cc", + "source/ulpfec_header_reader_writer.h", + "source/ulpfec_receiver_impl.cc", + "source/ulpfec_receiver_impl.h", + "source/video_codec_information.h", + ] + + if (rtc_enable_bwe_test_logging) { + defines = [ "BWE_TEST_LOGGING_COMPILE_TIME_ENABLE=1" ] + } else { + defines = [ "BWE_TEST_LOGGING_COMPILE_TIME_ENABLE=0" ] + } + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + deps = [ + "..:module_api", + "../..:webrtc_common", + "../../api:array_view", + "../../api:optional", + "../../api:transport_api", + "../../api/audio_codecs:audio_codecs_api", + "../../common_video", + "../../logging:rtc_event_log_api", + "../../rtc_base:gtest_prod", + "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_numerics", + "../../rtc_base:sequenced_task_checker", + "../../system_wrappers", + "../audio_coding:audio_format_conversion", + "../remote_bitrate_estimator", + ] + + if (!build_with_mozilla) { + deps += [ "../../api:libjingle_peerconnection_api" ] + } + + public_deps = [ + ":rtp_rtcp_format", + ] + + # TODO(jschuh): Bug 1348: fix this warning. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + if (is_win) { + cflags = [ + # TODO(kjellander): Bug 261: fix this warning. + "/wd4373", # virtual function override. + ] + } +} + +rtc_source_set("rtcp_transceiver") { + public = [ + "source/rtcp_transceiver.h", + "source/rtcp_transceiver_config.h", + "source/rtcp_transceiver_impl.h", + ] + sources = [ + "source/rtcp_transceiver.cc", + "source/rtcp_transceiver_config.cc", + "source/rtcp_transceiver_impl.cc", + ] + deps = [ + ":rtp_rtcp", + "../../api:array_view", + "../../api:optional", + "../../api:transport_api", + "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_task_queue", + "../../rtc_base:weak_ptr", + "../../system_wrappers:system_wrappers", + ] +} + +rtc_source_set("fec_test_helper") { + testonly = true + sources = [ + "source/fec_test_helper.cc", + "source/fec_test_helper.h", + ] + deps = [ + ":rtp_rtcp", + "..:module_api", + "../../rtc_base:rtc_base_approved", + ] + + # TODO(jschuh): bugs.webrtc.org/1348: fix this warning. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } +} + +rtc_source_set("mock_rtp_rtcp") { + testonly = true + sources = [ + "mocks/mock_recovered_packet_receiver.h", + "mocks/mock_rtcp_rtt_stats.h", + "mocks/mock_rtp_rtcp.h", + ] + deps = [ + ":rtp_rtcp", + "..:module_api", + "../../api:optional", + "../../rtc_base:rtc_base_approved", + "../../test:test_support", + ] +} + +if (rtc_include_tests) { + rtc_executable("test_packet_masks_metrics") { + testonly = true + + sources = [ + "test/testFec/average_residual_loss_xor_codes.h", + "test/testFec/test_packet_masks_metrics.cc", + ] + + deps = [ + ":rtp_rtcp", + "../../test:test_main", + "//testing/gtest", + ] + } # test_packet_masks_metrics + + rtc_source_set("rtp_rtcp_modules_tests") { + testonly = true + + sources = [ + "test/testFec/test_fec.cc", + ] + deps = [ + ":rtp_rtcp", + "../../rtc_base:rtc_base_approved", + "../../test:test_support", + ] + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + } + + rtc_source_set("rtp_rtcp_unittests") { + testonly = true + + sources = [ + "source/byte_io_unittest.cc", + "source/flexfec_header_reader_writer_unittest.cc", + "source/flexfec_receiver_unittest.cc", + "source/flexfec_sender_unittest.cc", + "source/nack_rtx_unittest.cc", + "source/packet_loss_stats_unittest.cc", + "source/playout_delay_oracle_unittest.cc", + "source/receive_statistics_unittest.cc", + "source/remote_ntp_time_estimator_unittest.cc", + "source/rtcp_nack_stats_unittest.cc", + "source/rtcp_packet/app_unittest.cc", + "source/rtcp_packet/bye_unittest.cc", + "source/rtcp_packet/common_header_unittest.cc", + "source/rtcp_packet/compound_packet_unittest.cc", + "source/rtcp_packet/dlrr_unittest.cc", + "source/rtcp_packet/extended_jitter_report_unittest.cc", + "source/rtcp_packet/extended_reports_unittest.cc", + "source/rtcp_packet/fir_unittest.cc", + "source/rtcp_packet/nack_unittest.cc", + "source/rtcp_packet/pli_unittest.cc", + "source/rtcp_packet/rapid_resync_request_unittest.cc", + "source/rtcp_packet/receiver_report_unittest.cc", + "source/rtcp_packet/remb_unittest.cc", + "source/rtcp_packet/report_block_unittest.cc", + "source/rtcp_packet/rrtr_unittest.cc", + "source/rtcp_packet/sdes_unittest.cc", + "source/rtcp_packet/sender_report_unittest.cc", + "source/rtcp_packet/target_bitrate_unittest.cc", + "source/rtcp_packet/tmmbn_unittest.cc", + "source/rtcp_packet/tmmbr_unittest.cc", + "source/rtcp_packet/transport_feedback_unittest.cc", + "source/rtcp_packet/voip_metric_unittest.cc", + "source/rtcp_packet_unittest.cc", + "source/rtcp_receiver_unittest.cc", + "source/rtcp_sender_unittest.cc", + "source/rtcp_transceiver_impl_unittest.cc", + "source/rtcp_transceiver_unittest.cc", + "source/rtp_fec_unittest.cc", + "source/rtp_format_h264_unittest.cc", + "source/rtp_format_video_generic_unittest.cc", + "source/rtp_format_vp8_test_helper.cc", + "source/rtp_format_vp8_test_helper.h", + "source/rtp_format_vp8_unittest.cc", + "source/rtp_format_vp9_unittest.cc", + "source/rtp_header_extension_map_unittest.cc", + "source/rtp_packet_history_unittest.cc", + "source/rtp_packet_unittest.cc", + "source/rtp_payload_registry_unittest.cc", + "source/rtp_receiver_unittest.cc", + "source/rtp_rtcp_impl_unittest.cc", + "source/rtp_sender_unittest.cc", + "source/rtp_utility_unittest.cc", + "source/time_util_unittest.cc", + "source/ulpfec_generator_unittest.cc", + "source/ulpfec_header_reader_writer_unittest.cc", + "source/ulpfec_receiver_unittest.cc", + "test/testAPI/test_api.cc", + "test/testAPI/test_api.h", + "test/testAPI/test_api_audio.cc", + "test/testAPI/test_api_rtcp.cc", + "test/testAPI/test_api_video.cc", + ] + deps = [ + ":fec_test_helper", + ":mock_rtp_rtcp", + ":rtcp_transceiver", + ":rtp_rtcp", + "..:module_api", + "../..:webrtc_common", + "../../api:array_view", + "../../api:optional", + "../../api:transport_api", + "../../call:rtp_receiver", + "../../common_video:common_video", + "../../logging:rtc_event_log_api", + "../../rtc_base:rtc_base_approved", + "../../rtc_base:rtc_base_tests_utils", + "../../rtc_base:rtc_task_queue", + "../../system_wrappers:system_wrappers", + "../../test:field_trial", + "../../test:rtp_test_utils", + "../../test:test_common", + "../../test:test_support", + "../audio_coding:audio_format_conversion", + "//testing/gmock", + ] + + if (!build_with_mozilla) { + deps += [ "../../api:libjingle_peerconnection_api" ] + } + + # TODO(jschuh): bugs.webrtc.org/1348: fix this warning. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + } +} diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/DEPS b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/DEPS new file mode 100644 index 0000000000..9d9f33cbaf --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/DEPS @@ -0,0 +1,6 @@ +include_rules = [ + "+call", + "+common_video", + "+logging/rtc_event_log", + "+system_wrappers", +] diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/OWNERS b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/OWNERS new file mode 100644 index 0000000000..9377d87f11 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/OWNERS @@ -0,0 +1,10 @@ +stefan@webrtc.org +henrik.lundin@webrtc.org +mflodman@webrtc.org +asapersson@webrtc.org +danilchap@webrtc.org + +# These are for the common case of adding or renaming files. If you're doing +# structural changes, please get a review from a reviewer in this file. +per-file *.gn=* +per-file *.gni=* diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_receiver.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_receiver.h new file mode 100644 index 0000000000..024d691bf9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_receiver.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_INCLUDE_FLEXFEC_RECEIVER_H_ +#define MODULES_RTP_RTCP_INCLUDE_FLEXFEC_RECEIVER_H_ + +#include <memory> + +#include "modules/rtp_rtcp/include/ulpfec_receiver.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/sequenced_task_checker.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +class FlexfecReceiver { + public: + FlexfecReceiver(uint32_t ssrc, + uint32_t protected_media_ssrc, + RecoveredPacketReceiver* recovered_packet_receiver); + ~FlexfecReceiver(); + + // Inserts a received packet (can be either media or FlexFEC) into the + // internal buffer, and sends the received packets to the erasure code. + // All newly recovered packets are sent back through the callback. + void OnRtpPacket(const RtpPacketReceived& packet); + + // Returns a counter describing the added and recovered packets. + FecPacketCounter GetPacketCounter() const; + + // Protected to aid testing. + protected: + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> AddReceivedPacket( + const RtpPacketReceived& packet); + void ProcessReceivedPacket( + const ForwardErrorCorrection::ReceivedPacket& received_packet); + + private: + // Config. + const uint32_t ssrc_; + const uint32_t protected_media_ssrc_; + + // Erasure code interfacing and callback. + std::unique_ptr<ForwardErrorCorrection> erasure_code_ + RTC_GUARDED_BY(sequence_checker_); + ForwardErrorCorrection::RecoveredPacketList recovered_packets_ + RTC_GUARDED_BY(sequence_checker_); + RecoveredPacketReceiver* const recovered_packet_receiver_; + + // Logging and stats. + Clock* const clock_; + int64_t last_recovered_packet_ms_ RTC_GUARDED_BY(sequence_checker_); + FecPacketCounter packet_counter_ RTC_GUARDED_BY(sequence_checker_); + + rtc::SequencedTaskChecker sequence_checker_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_INCLUDE_FLEXFEC_RECEIVER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_sender.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_sender.h new file mode 100644 index 0000000000..5b939d534b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_sender.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_ +#define MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_ + +#include <memory> +#include <vector> + +#include "api/array_view.h" +#include "api/rtpparameters.h" +#include "modules/include/module_common_types.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_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "modules/rtp_rtcp/source/ulpfec_generator.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/random.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +class RtpPacketToSend; + +// Note that this class is not thread safe, and thus requires external +// synchronization. Currently, this is done using the lock in PayloadRouter. + +class FlexfecSender { + public: + FlexfecSender(int payload_type, + uint32_t ssrc, + uint32_t protected_media_ssrc, + const std::vector<RtpExtension>& rtp_header_extensions, + rtc::ArrayView<const RtpExtensionSize> extension_sizes, + const RtpState* rtp_state, + Clock* clock); + ~FlexfecSender(); + + uint32_t ssrc() const { return ssrc_; } + + // Sets the FEC rate, max frames sent before FEC packets are sent, + // and what type of generator matrices are used. + void SetFecParameters(const FecProtectionParams& params); + + // Adds a media packet to the internal buffer. When enough media packets + // have been added, the FEC packets are generated and stored internally. + // These FEC packets are then obtained by calling GetFecPackets(). + // Returns true if the media packet was successfully added. + bool AddRtpPacketAndGenerateFec(const RtpPacketToSend& packet); + + // Returns true if there are generated FEC packets available. + bool FecAvailable() const; + + // Returns generated FlexFEC packets. + std::vector<std::unique_ptr<RtpPacketToSend>> GetFecPackets(); + + // Returns the overhead, per packet, for FlexFEC. + size_t MaxPacketOverhead() const; + + // Only called on the VideoSendStream queue, after operation has shut down. + RtpState GetRtpState(); + + private: + // Utility. + Clock* const clock_; + Random random_; + int64_t last_generated_packet_ms_; + + // Config. + const int payload_type_; + const uint32_t timestamp_offset_; + const uint32_t ssrc_; + const uint32_t protected_media_ssrc_; + // Sequence number of next packet to generate. + uint16_t seq_num_; + + // Implementation. + UlpfecGenerator ulpfec_generator_; + const RtpHeaderExtensionMap rtp_header_extension_map_; + const size_t header_extensions_size_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/receive_statistics.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/receive_statistics.h new file mode 100644 index 0000000000..ee7dbbbd8d --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/receive_statistics.h @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#ifndef MODULES_RTP_RTCP_INCLUDE_RECEIVE_STATISTICS_H_ +#define MODULES_RTP_RTCP_INCLUDE_RECEIVE_STATISTICS_H_ + +#include <map> +#include <vector> + +#include "modules/include/module.h" +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class Clock; + +class ReceiveStatisticsProvider { + public: + virtual ~ReceiveStatisticsProvider() = default; + // Collects receive statistic in a form of rtcp report blocks. + // Returns at most |max_blocks| report blocks. + virtual std::vector<rtcp::ReportBlock> RtcpReportBlocks( + size_t max_blocks) = 0; +}; + +class StreamStatistician { + public: + virtual ~StreamStatistician(); + + virtual bool GetStatistics(RtcpStatistics* statistics, bool reset) = 0; + virtual void GetDataCounters(size_t* bytes_received, + uint32_t* packets_received) const = 0; + + // Gets received stream data counters (includes reset counter values). + virtual void GetReceiveStreamDataCounters( + StreamDataCounters* data_counters) const = 0; + + virtual uint32_t BitrateReceived() const = 0; + + // Returns true if the packet with RTP header |header| is likely to be a + // retransmitted packet, false otherwise. + virtual bool IsRetransmitOfOldPacket(const RTPHeader& header, + int64_t min_rtt) const = 0; + + // Returns true if |sequence_number| is received in order, false otherwise. + virtual bool IsPacketInOrder(uint16_t sequence_number) const = 0; +}; + +class ReceiveStatistics : public ReceiveStatisticsProvider { + public: + ~ReceiveStatistics() override = default; + + static ReceiveStatistics* Create(Clock* clock); + + // Updates the receive statistics with this packet. + virtual void IncomingPacket(const RTPHeader& rtp_header, + size_t packet_length, + bool retransmitted) = 0; + + // Increment counter for number of FEC packets received. + virtual void FecPacketReceived(const RTPHeader& header, + size_t packet_length) = 0; + + // Returns a pointer to the statistician of an ssrc. + virtual StreamStatistician* GetStatistician(uint32_t ssrc) const = 0; + + // Sets the max reordering threshold in number of packets. + virtual void SetMaxReorderingThreshold(int max_reordering_threshold) = 0; + + // Called on new RTCP stats creation. + virtual void RegisterRtcpStatisticsCallback( + RtcpStatisticsCallback* callback) = 0; + + // Called on new RTP stats creation. + virtual void RegisterRtpStatisticsCallback( + StreamDataCountersCallback* callback) = 0; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_INCLUDE_RECEIVE_STATISTICS_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h new file mode 100644 index 0000000000..e3d95b20ca --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h @@ -0,0 +1,53 @@ +/* + * 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_RTP_RTCP_INCLUDE_REMOTE_NTP_TIME_ESTIMATOR_H_ +#define MODULES_RTP_RTCP_INCLUDE_REMOTE_NTP_TIME_ESTIMATOR_H_ + +#include <memory> + +#include "rtc_base/constructormagic.h" +#include "rtc_base/numerics/moving_median_filter.h" +#include "system_wrappers/include/rtp_to_ntp_estimator.h" + +namespace webrtc { + +class Clock; + +// RemoteNtpTimeEstimator can be used to estimate a given RTP timestamp's NTP +// time in local timebase. +// Note that it needs to be trained with at least 2 RTCP SR (by calling +// |UpdateRtcpTimestamp|) before it can be used. +class RemoteNtpTimeEstimator { + public: + explicit RemoteNtpTimeEstimator(Clock* clock); + + ~RemoteNtpTimeEstimator(); + + // Updates the estimator with round trip time |rtt|, NTP seconds |ntp_secs|, + // NTP fraction |ntp_frac| and RTP timestamp |rtcp_timestamp|. + bool UpdateRtcpTimestamp(int64_t rtt, uint32_t ntp_secs, uint32_t ntp_frac, + uint32_t rtp_timestamp); + + // Estimates the NTP timestamp in local timebase from |rtp_timestamp|. + // Returns the NTP timestamp in ms when success. -1 if failed. + int64_t Estimate(uint32_t rtp_timestamp); + + private: + Clock* clock_; + MovingMedianFilter<int64_t> ntp_clocks_offset_estimator_; + RtpToNtpEstimator rtp_to_ntp_; + int64_t last_timing_log_ms_; + RTC_DISALLOW_COPY_AND_ASSIGN(RemoteNtpTimeEstimator); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_INCLUDE_REMOTE_NTP_TIME_ESTIMATOR_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_cvo.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_cvo.h new file mode 100644 index 0000000000..bc0b4ee95c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_cvo.h @@ -0,0 +1,56 @@ +/* + * 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 MODULES_RTP_RTCP_INCLUDE_RTP_CVO_H_ +#define MODULES_RTP_RTCP_INCLUDE_RTP_CVO_H_ + +#include "api/video/video_rotation.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +// Please refer to http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/ +// 12.07.00_60/ts_126114v120700p.pdf Section 7.4.5. The rotation of a frame is +// the clockwise angle the frames must be rotated in order to display the frames +// correctly if the display is rotated in its natural orientation. +inline uint8_t ConvertVideoRotationToCVOByte(VideoRotation rotation) { + switch (rotation) { + case kVideoRotation_0: + return 0; + case kVideoRotation_90: + return 1; + case kVideoRotation_180: + return 2; + case kVideoRotation_270: + return 3; + } + RTC_NOTREACHED(); + return 0; +} + +inline VideoRotation ConvertCVOByteToVideoRotation(uint8_t cvo_byte) { + // CVO byte: |0 0 0 0 C F R R|. + const uint8_t rotation_bits = cvo_byte & 0x3; + switch (rotation_bits) { + case 0: + return kVideoRotation_0; + case 1: + return kVideoRotation_90; + case 2: + return kVideoRotation_180; + case 3: + return kVideoRotation_270; + default: + RTC_NOTREACHED(); + return kVideoRotation_0; + } +} + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_INCLUDE_RTP_CVO_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_extension_map.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_extension_map.h new file mode 100644 index 0000000000..efac056322 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_extension_map.h @@ -0,0 +1,80 @@ +/* + * 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 MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_EXTENSION_MAP_H_ +#define MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_EXTENSION_MAP_H_ + +#include <string> + +#include "api/array_view.h" +#include "api/rtpparameters.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +struct RtpExtensionSize { + RTPExtensionType type; + uint8_t value_size; +}; + +class RtpHeaderExtensionMap { + public: + static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone; + static constexpr int kInvalidId = 0; + + RtpHeaderExtensionMap(); + explicit RtpHeaderExtensionMap(rtc::ArrayView<const RtpExtension> extensions); + + template <typename Extension> + bool Register(int id) { + return Register(id, Extension::kId, Extension::kUri); + } + bool RegisterByType(int id, RTPExtensionType type); + bool RegisterByUri(int id, const std::string& uri); + + bool IsRegistered(RTPExtensionType type) const { + return GetId(type) != kInvalidId; + } + // Return kInvalidType if not found. + RTPExtensionType GetType(int id) const { + RTC_DCHECK_GE(id, kMinId); + RTC_DCHECK_LE(id, kMaxId); + return types_[id]; + } + // Return kInvalidId if not found. + uint8_t GetId(RTPExtensionType type) const { + RTC_DCHECK_GT(type, kRtpExtensionNone); + RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions); + return ids_[type]; + } + + size_t GetTotalLengthInBytes( + rtc::ArrayView<const RtpExtensionSize> extensions) const; + + // TODO(danilchap): Remove use of the functions below. + int32_t Register(RTPExtensionType type, int id) { + return RegisterByType(id, type) ? 0 : -1; + } + int32_t Deregister(RTPExtensionType type); + + private: + static constexpr int kMinId = 1; + static constexpr int kMaxId = 14; + bool Register(int id, RTPExtensionType type, const char* uri); + + RTPExtensionType types_[kMaxId + 1]; + uint8_t ids_[kRtpExtensionNumberOfExtensions]; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_EXTENSION_MAP_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_parser.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_parser.h new file mode 100644 index 0000000000..3b7dc7f573 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_parser.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_ +#define MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_ + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +struct RTPHeader; + +class RtpHeaderParser { + public: + static RtpHeaderParser* Create(); + virtual ~RtpHeaderParser() {} + + // Returns true if the packet is an RTCP packet, false otherwise. + static bool IsRtcp(const uint8_t* packet, size_t length); + + // Parses the packet and stores the parsed packet in |header|. Returns true on + // success, false otherwise. + // This method is thread-safe in the sense that it can parse multiple packets + // at once. + virtual bool Parse(const uint8_t* packet, + size_t length, + RTPHeader* header, + bool secured = false) const = 0; + + // Registers an RTP header extension and binds it to |id|. + virtual bool RegisterRtpHeaderExtension(RTPExtensionType type, + uint8_t id) = 0; + + // De-registers an RTP header extension. + virtual bool DeregisterRtpHeaderExtension(RTPExtensionType type) = 0; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_packet_observer.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_packet_observer.h new file mode 100644 index 0000000000..0eae1f8020 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_packet_observer.h @@ -0,0 +1,19 @@ +#ifndef RTP_AUDIO_LEVEL_OBSERVER_H +#define RTP_AUDIO_LEVEL_OBSERVER_H + +namespace webrtc { + +struct RTPHeader; + +class RtpPacketObserver { + public: + + virtual void + OnRtpPacket(const RTPHeader& aRtpHeader, + const int64_t aTimestamp, + const uint32_t aJitter) = 0; +}; + +} + +#endif // RTP_AUDIO_LEVEL_OBSERVER_H diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h new file mode 100644 index 0000000000..942c4ff1e7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h @@ -0,0 +1,130 @@ +/* + * 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. + */ + +#ifndef MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_ +#define MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_ + +#include <map> +#include <set> + +#include "api/audio_codecs/audio_format.h" +#include "api/optional.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/criticalsection.h" + +namespace webrtc { + +class VideoCodec; + +class RTPPayloadRegistry { + public: + RTPPayloadRegistry(); + ~RTPPayloadRegistry(); + + // TODO(magjed): Split RTPPayloadRegistry into separate Audio and Video class + // and simplify the code. http://crbug/webrtc/6743. + + // Replace all audio receive payload types with the given map. + void SetAudioReceivePayloads(std::map<int, SdpAudioFormat> codecs); + + int32_t RegisterReceivePayload(int payload_type, + const SdpAudioFormat& audio_format, + bool* created_new_payload_type); + int32_t RegisterReceivePayload(const VideoCodec& video_codec); + + int32_t DeRegisterReceivePayload(int8_t payload_type); + + int32_t ReceivePayloadType(const SdpAudioFormat& audio_format, + int8_t* payload_type) const; + int32_t ReceivePayloadType(const VideoCodec& video_codec, + int8_t* payload_type) const; + + bool RtxEnabled() const; + + void SetRtxSsrc(uint32_t ssrc); + + bool GetRtxSsrc(uint32_t* ssrc) const; + + void SetRtxPayloadType(int payload_type, int associated_payload_type); + + bool IsRed(const RTPHeader& header) const; + + int GetPayloadTypeFrequency(uint8_t payload_type) const; + + rtc::Optional<RtpUtility::Payload> PayloadTypeToPayload( + uint8_t payload_type) const; + + void ResetLastReceivedPayloadTypes() { + rtc::CritScope cs(&crit_sect_); + last_received_payload_type_ = -1; + last_received_media_payload_type_ = -1; + } + + // This sets the payload type of the packets being received from the network + // on the media SSRC. For instance if packets are encapsulated with RED, this + // payload type will be the RED payload type. + void SetIncomingPayloadType(const RTPHeader& header); + + // Returns true if the new media payload type has not changed. + bool ReportMediaPayloadType(uint8_t media_payload_type); + + int8_t red_payload_type() const { return GetPayloadTypeWithName("red"); } + int8_t ulpfec_payload_type() const { + return GetPayloadTypeWithName("ulpfec"); + } + int8_t last_received_payload_type() const { + rtc::CritScope cs(&crit_sect_); + return last_received_payload_type_; + } + void set_last_received_payload_type(int8_t last_received_payload_type) { + rtc::CritScope cs(&crit_sect_); + last_received_payload_type_ = last_received_payload_type; + } + + int8_t last_received_media_payload_type() const { + rtc::CritScope cs(&crit_sect_); + return last_received_media_payload_type_; + } + + private: + // Prunes the payload type map of the specific payload type, if it exists. + void DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( + const SdpAudioFormat& audio_format); + + bool IsRtxInternal(const RTPHeader& header) const; + // Returns the payload type for the payload with name |payload_name|, or -1 if + // no such payload is registered. + int8_t GetPayloadTypeWithName(const char* payload_name) const; + + rtc::CriticalSection crit_sect_; + std::map<int, RtpUtility::Payload> payload_type_map_; + int8_t incoming_payload_type_; + int8_t last_received_payload_type_; + int8_t last_received_media_payload_type_; + bool rtx_; + // Mapping rtx_payload_type_map_[rtx] = associated. + std::map<int, int> rtx_payload_type_map_; + uint32_t ssrc_rtx_; + // Only warn once per payload type, if an RTX packet is received but + // no associated payload type found in |rtx_payload_type_map_|. + std::set<int> payload_types_with_suppressed_warnings_ + RTC_GUARDED_BY(crit_sect_); + + // As a first step in splitting this class up in separate cases for audio and + // video, DCHECK that no instance is used for both audio and video. +#if RTC_DCHECK_IS_ON + bool used_for_audio_ RTC_GUARDED_BY(crit_sect_) = false; + bool used_for_video_ RTC_GUARDED_BY(crit_sect_) = false; +#endif +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_receiver.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_receiver.h new file mode 100644 index 0000000000..3881ef7998 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_receiver.h @@ -0,0 +1,115 @@ +/* + * 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 MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_ +#define MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_ + +#include <vector> + +#include "api/rtpreceiverinterface.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class RTPPayloadRegistry; +class VideoCodec; + +class TelephoneEventHandler { + public: + virtual ~TelephoneEventHandler() {} + + // The following three methods implement the TelephoneEventHandler interface. + // Forward DTMFs to decoder for playout. + virtual void SetTelephoneEventForwardToDecoder(bool forward_to_decoder) = 0; + + // Is forwarding of outband telephone events turned on/off? + virtual bool TelephoneEventForwardToDecoder() const = 0; + + // Is TelephoneEvent configured with payload type payload_type + virtual bool TelephoneEventPayloadType(const int8_t payload_type) const = 0; +}; + +class RtpReceiver { + public: + // Creates a video-enabled RTP receiver. + static RtpReceiver* CreateVideoReceiver( + Clock* clock, + RtpData* incoming_payload_callback, + RtpFeedback* incoming_messages_callback, + RTPPayloadRegistry* rtp_payload_registry); + + // Creates an audio-enabled RTP receiver. + static RtpReceiver* CreateAudioReceiver( + Clock* clock, + RtpData* incoming_payload_callback, + RtpFeedback* incoming_messages_callback, + RTPPayloadRegistry* rtp_payload_registry); + + virtual ~RtpReceiver() {} + + // Returns a TelephoneEventHandler if available. + virtual TelephoneEventHandler* GetTelephoneEventHandler() = 0; + + // Registers a receive payload in the payload registry and notifies the media + // receiver strategy. + virtual int32_t RegisterReceivePayload( + int payload_type, + const SdpAudioFormat& audio_format) = 0; + + // Deprecated version of the above. + int32_t RegisterReceivePayload(const CodecInst& audio_codec); + + // Registers a receive payload in the payload registry. + virtual int32_t RegisterReceivePayload(const VideoCodec& video_codec) = 0; + + // De-registers |payload_type| from the payload registry. + virtual int32_t DeRegisterReceivePayload(const int8_t payload_type) = 0; + + // Parses the media specific parts of an RTP packet and updates the receiver + // state. This for instance means that any changes in SSRC and payload type is + // detected and acted upon. + virtual bool IncomingRtpPacket(const RTPHeader& rtp_header, + const uint8_t* payload, + size_t payload_length, + PayloadUnion payload_specific) = 0; + // TODO(nisse): Deprecated version, delete as soon as downstream + // applications are updated. + bool IncomingRtpPacket(const RTPHeader& rtp_header, + const uint8_t* payload, + size_t payload_length, + PayloadUnion payload_specific, + bool in_order /* Ignored */) { + return IncomingRtpPacket(rtp_header, payload, payload_length, + payload_specific); + } + + // Gets the RTP timestamp and the corresponding monotonic system + // time for the most recent in-order packet. Returns true on + // success, false if no packet has been received. + virtual bool GetLatestTimestamps(uint32_t* timestamp, + int64_t* receive_time_ms) const = 0; + + // Returns the remote SSRC of the currently received RTP stream. + virtual uint32_t SSRC() const = 0; + + // Returns the current remote CSRCs. + virtual int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const = 0; + + virtual void GetRID(char rid[256]) const = 0; + + // Returns the current energy of the RTP stream received. + virtual int32_t Energy(uint8_t array_of_energy[kRtpCsrcSize]) const = 0; + + virtual std::vector<RtpSource> GetSources() const = 0; +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h new file mode 100644 index 0000000000..8cd56b4010 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h @@ -0,0 +1,466 @@ +/* + * 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 MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_H_ +#define MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_H_ + +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "api/optional.h" +#include "common_types.h" // NOLINT(build/include) +#include "modules/include/module.h" +#include "modules/rtp_rtcp/include/flexfec_sender.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/deprecation.h" + +namespace webrtc { + +// Forward declarations. +class OverheadObserver; +class RateLimiter; +class ReceiveStatisticsProvider; +class RemoteBitrateEstimator; +class RtcEventLog; +class RtpReceiver; +class Transport; +class VideoBitrateAllocationObserver; + +RTPExtensionType StringToRtpExtensionType(const std::string& extension); + +namespace rtcp { +class TransportFeedback; +} + +class RtpRtcp : public Module { + public: + struct Configuration { + Configuration(); + + // True for a audio version of the RTP/RTCP module object false will create + // a video version. + bool audio = false; + bool receiver_only = false; + + // The clock to use to read time. If nullptr then system clock will be used. + Clock* clock = nullptr; + + ReceiveStatisticsProvider* receive_statistics = nullptr; + + // Transport object that will be called when packets are ready to be sent + // out on the network. + Transport* outgoing_transport = nullptr; + + // Called when the receiver request a intra frame. + RtcpIntraFrameObserver* intra_frame_callback = nullptr; + + // Called when we receive a changed estimate from the receiver of out + // stream. + RtcpBandwidthObserver* bandwidth_callback = nullptr; + + // Called when we receive a RTCP bye or timeout + RtcpEventObserver* event_callback = nullptr; + + TransportFeedbackObserver* transport_feedback_callback = nullptr; + VideoBitrateAllocationObserver* bitrate_allocation_observer = nullptr; + RtcpRttStats* rtt_stats = nullptr; + RtcpPacketTypeCounterObserver* rtcp_packet_type_counter_observer = nullptr; + + // Estimates the bandwidth available for a set of streams from the same + // client. + RemoteBitrateEstimator* remote_bitrate_estimator = nullptr; + + // Spread any bursts of packets into smaller bursts to minimize packet loss. + RtpPacketSender* paced_sender = nullptr; + + // Generate FlexFEC packets. + // TODO(brandtr): Remove when FlexfecSender is wired up to PacedSender. + FlexfecSender* flexfec_sender = nullptr; + + TransportSequenceNumberAllocator* transport_sequence_number_allocator = + nullptr; + BitrateStatisticsObserver* send_bitrate_observer = nullptr; + FrameCountObserver* send_frame_count_observer = nullptr; + SendSideDelayObserver* send_side_delay_observer = nullptr; + RtcEventLog* event_log = nullptr; + SendPacketObserver* send_packet_observer = nullptr; + RateLimiter* retransmission_rate_limiter = nullptr; + OverheadObserver* overhead_observer = nullptr; + RtpKeepAliveConfig keepalive_config; + + private: + RTC_DISALLOW_COPY_AND_ASSIGN(Configuration); + }; + + // Create a RTP/RTCP module object using the system clock. + // |configuration| - Configuration of the RTP/RTCP module. + static RtpRtcp* CreateRtpRtcp(const RtpRtcp::Configuration& configuration); + + // ************************************************************************** + // Receiver functions + // ************************************************************************** + + virtual void IncomingRtcpPacket(const uint8_t* incoming_packet, + size_t incoming_packet_length) = 0; + + virtual void SetRemoteSSRC(uint32_t ssrc) = 0; + + // ************************************************************************** + // Sender + // ************************************************************************** + + // Sets the maximum size of an RTP packet, including RTP headers. + virtual void SetMaxRtpPacketSize(size_t size) = 0; + + // Returns max RTP packet size. Takes into account RTP headers and + // FEC/ULP/RED overhead (when FEC is enabled). + virtual size_t MaxRtpPacketSize() const = 0; + + // Sets codec name and payload type. Returns -1 on failure else 0. + virtual int32_t RegisterSendPayload(const CodecInst& voice_codec) = 0; + + // Sets codec name and payload type. Return -1 on failure else 0. + virtual int32_t RegisterSendPayload(const VideoCodec& video_codec) = 0; + + virtual void RegisterVideoSendPayload(int payload_type, + const char* payload_name) = 0; + + // Unregisters a send payload. + // |payload_type| - payload type of codec + // Returns -1 on failure else 0. + virtual int32_t DeRegisterSendPayload(int8_t payload_type) = 0; + + // (De)registers RTP header extension type and id. + // Returns -1 on failure else 0. + virtual int32_t RegisterSendRtpHeaderExtension(RTPExtensionType type, + uint8_t id) = 0; + + virtual int32_t DeregisterSendRtpHeaderExtension(RTPExtensionType type) = 0; + + virtual bool HasBweExtensions() const = 0; + + // Returns start timestamp. + virtual uint32_t StartTimestamp() const = 0; + + // Sets start timestamp. Start timestamp is set to a random value if this + // function is never called. + virtual void SetStartTimestamp(uint32_t timestamp) = 0; + + // Returns SequenceNumber. + virtual uint16_t SequenceNumber() const = 0; + + // Sets SequenceNumber, default is a random number. + virtual void SetSequenceNumber(uint16_t seq) = 0; + + virtual void SetRtpState(const RtpState& rtp_state) = 0; + virtual void SetRtxState(const RtpState& rtp_state) = 0; + virtual RtpState GetRtpState() const = 0; + virtual RtpState GetRtxState() const = 0; + + // Returns SSRC. + virtual uint32_t SSRC() const = 0; + + // Set RID value for the RID header extension or RTCP SDES + virtual int32_t SetRID(const char *rid) = 0; + // Set MID value for the MID header extension + virtual int32_t SetMID(const char *mid) = 0; + + // Sets SSRC, default is a random number. + virtual void SetSSRC(uint32_t ssrc) = 0; + + // Sets CSRC. + // |csrcs| - vector of CSRCs + virtual void SetCsrcs(const std::vector<uint32_t>& csrcs) = 0; + + // Turns on/off sending RTX (RFC 4588). The modes can be set as a combination + // of values of the enumerator RtxMode. + virtual void SetRtxSendStatus(int modes) = 0; + + // Returns status of sending RTX (RFC 4588). The returned value can be + // a combination of values of the enumerator RtxMode. + virtual int RtxSendStatus() const = 0; + + // Sets the SSRC to use when sending RTX packets. This doesn't enable RTX, + // only the SSRC is set. + virtual void SetRtxSsrc(uint32_t ssrc) = 0; + + // Sets the payload type to use when sending RTX packets. Note that this + // doesn't enable RTX, only the payload type is set. + virtual void SetRtxSendPayloadType(int payload_type, + int associated_payload_type) = 0; + + // Returns the FlexFEC SSRC, if there is one. + virtual rtc::Optional<uint32_t> FlexfecSsrc() const = 0; + + // Sets sending status. Sends kRtcpByeCode when going from true to false. + // Returns -1 on failure else 0. + virtual int32_t SetSendingStatus(bool sending) = 0; + + // Returns current sending status. + virtual bool Sending() const = 0; + + // Starts/Stops media packets. On by default. + virtual void SetSendingMediaStatus(bool sending) = 0; + + // Returns current media sending status. + virtual bool SendingMedia() const = 0; + + // Returns current bitrate in Kbit/s. + virtual void BitrateSent(uint32_t* total_rate, + uint32_t* video_rate, + uint32_t* fec_rate, + uint32_t* nack_rate) const = 0; + + // Used by the codec module to deliver a video or audio frame for + // packetization. + // |frame_type| - type of frame to send + // |payload_type| - payload type of frame to send + // |timestamp| - timestamp of frame to send + // |payload_data| - payload buffer of frame to send + // |payload_size| - size of payload buffer to send + // |fragmentation| - fragmentation offset data for fragmented frames such + // as layers or RED + // |transport_frame_id_out| - set to RTP timestamp. + // Returns true on success. + virtual bool SendOutgoingData(FrameType frame_type, + int8_t payload_type, + uint32_t timestamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* rtp_video_header, + uint32_t* transport_frame_id_out) = 0; + + virtual bool TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission, + const PacedPacketInfo& pacing_info) = 0; + + virtual size_t TimeToSendPadding(size_t bytes, + const PacedPacketInfo& pacing_info) = 0; + + // Called on generation of new statistics after an RTP send. + virtual void RegisterSendChannelRtpStatisticsCallback( + StreamDataCountersCallback* callback) = 0; + virtual StreamDataCountersCallback* GetSendChannelRtpStatisticsCallback() + const = 0; + + // ************************************************************************** + // RTCP + // ************************************************************************** + + // Returns RTCP status. + virtual RtcpMode RTCP() const = 0; + + // Sets RTCP status i.e on(compound or non-compound)/off. + // |method| - RTCP method to use. + virtual void SetRTCPStatus(RtcpMode method) = 0; + + // Sets RTCP CName (i.e unique identifier). + // Returns -1 on failure else 0. + virtual int32_t SetCNAME(const char* cname) = 0; + + // Returns remote CName. + // Returns -1 on failure else 0. + virtual int32_t RemoteCNAME(uint32_t remote_ssrc, + char cname[RTCP_CNAME_SIZE]) const = 0; + + // Returns remote NTP. + // Returns -1 on failure else 0. + virtual int32_t RemoteNTP(uint32_t* received_ntp_secs, + uint32_t* received_ntp_frac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp) const = 0; + + // Returns -1 on failure else 0. + virtual int32_t AddMixedCNAME(uint32_t ssrc, const char* cname) = 0; + + // Returns -1 on failure else 0. + virtual int32_t RemoveMixedCNAME(uint32_t ssrc) = 0; + + // Returns current RTT (round-trip time) estimate. + // Returns -1 on failure else 0. + virtual int32_t RTT(uint32_t remote_ssrc, + int64_t* rtt, + int64_t* avg_rtt, + int64_t* min_rtt, + int64_t* max_rtt) const = 0; + + // Forces a send of a RTCP packet. Periodic SR and RR are triggered via the + // process function. + // Returns -1 on failure else 0. + virtual int32_t SendRTCP(RTCPPacketType rtcp_packet_type) = 0; + + // Forces a send of a RTCP packet with more than one packet type. + // periodic SR and RR are triggered via the process function + // Returns -1 on failure else 0. + virtual int32_t SendCompoundRTCP( + const std::set<RTCPPacketType>& rtcp_packet_types) = 0; + + // Returns statistics of the amount of data sent. + // Returns -1 on failure else 0. + virtual int32_t DataCountersRTP(size_t* bytes_sent, + uint32_t* packets_sent) const = 0; + + // Returns send statistics for the RTP and RTX stream. + virtual void GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const = 0; + + // Returns packet loss statistics for the RTP stream. + virtual void GetRtpPacketLossStats( + bool outgoing, + uint32_t ssrc, + struct RtpPacketLossStats* loss_stats) const = 0; + + // Returns packet count, octet count, and timestamp from RTCP sender report. + virtual void RemoteRTCPSenderInfo(uint32_t* packet_count, + uint32_t* octet_count, + NtpTime* ntp_timestamp) const = 0; + + // Returns received RTCP report block. + // Returns -1 on failure else 0. + virtual int32_t RemoteRTCPStat( + std::vector<RTCPReportBlock>* receive_blocks) const = 0; + + // (APP) Sets application specific data. + // Returns -1 on failure else 0. + virtual int32_t SetRTCPApplicationSpecificData(uint8_t sub_type, + uint32_t name, + const uint8_t* data, + uint16_t length) = 0; + // (XR) Sets VOIP metric. + // Returns -1 on failure else 0. + virtual int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) = 0; + + // (XR) Sets Receiver Reference Time Report (RTTR) status. + virtual void SetRtcpXrRrtrStatus(bool enable) = 0; + + // Returns current Receiver Reference Time Report (RTTR) status. + virtual bool RtcpXrRrtrStatus() const = 0; + + // (REMB) Receiver Estimated Max Bitrate. + // Schedules sending REMB on next and following sender/receiver reports. + virtual void SetRemb(uint32_t bitrate_bps, + const std::vector<uint32_t>& ssrcs) = 0; + // Stops sending REMB on next and following sender/receiver reports. + virtual void UnsetRemb() = 0; + + // (TMMBR) Temporary Max Media Bit Rate + virtual bool TMMBR() const = 0; + + virtual void SetTMMBRStatus(bool enable) = 0; + + // (NACK) + + // TODO(holmer): Propagate this API to VideoEngine. + // Returns the currently configured selective retransmission settings. + virtual int SelectiveRetransmissions() const = 0; + + // TODO(holmer): Propagate this API to VideoEngine. + // Sets the selective retransmission settings, which will decide which + // packets will be retransmitted if NACKed. Settings are constructed by + // combining the constants in enum RetransmissionMode with bitwise OR. + // All packets are retransmitted if kRetransmitAllPackets is set, while no + // packets are retransmitted if kRetransmitOff is set. + // By default all packets except FEC packets are retransmitted. For VP8 + // with temporal scalability only base layer packets are retransmitted. + // Returns -1 on failure, otherwise 0. + virtual int SetSelectiveRetransmissions(uint8_t settings) = 0; + + // Sends a Negative acknowledgement packet. + // Returns -1 on failure else 0. + // TODO(philipel): Deprecate this and start using SendNack instead, mostly + // because we want a function that actually send NACK for the specified + // packets. + virtual int32_t SendNACK(const uint16_t* nack_list, uint16_t size) = 0; + + // Sends NACK for the packets specified. + // Note: This assumes the caller keeps track of timing and doesn't rely on + // the RTP module to do this. + virtual void SendNack(const std::vector<uint16_t>& sequence_numbers) = 0; + + // Store the sent packets, needed to answer to a Negative acknowledgment + // requests. + virtual void SetStorePacketsStatus(bool enable, uint16_t numberToStore) = 0; + + // Returns true if the module is configured to store packets. + virtual bool StorePackets() const = 0; + + // Called on receipt of RTCP report block from remote side. + virtual void RegisterRtcpStatisticsCallback( + RtcpStatisticsCallback* callback) = 0; + virtual RtcpStatisticsCallback* GetRtcpStatisticsCallback() = 0; + // BWE feedback packets. + virtual bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) = 0; + + virtual void SetVideoBitrateAllocation(const BitrateAllocation& bitrate) = 0; + + // ************************************************************************** + // Audio + // ************************************************************************** + + // Sends a TelephoneEvent tone using RFC 2833 (4733). + // Returns -1 on failure else 0. + virtual int32_t SendTelephoneEventOutband(uint8_t key, + uint16_t time_ms, + uint8_t level) = 0; + + // Store the audio level in dBov for header-extension-for-audio-level- + // indication. + // This API shall be called before transmision of an RTP packet to ensure + // that the |level| part of the extended RTP header is updated. + // return -1 on failure else 0. + virtual int32_t SetAudioLevel(uint8_t level_dbov) = 0; + + // ************************************************************************** + // Video + // ************************************************************************** + + // Set RED and ULPFEC payload types. A payload type of -1 means that the + // corresponding feature is turned off. Note that we DO NOT support enabling + // ULPFEC without enabling RED. However, we DO support enabling RED without + // enabling ULPFEC. This is due to an RED/RTX workaround, where the receiver + // assumes that RTX packets carry RED if RED has been configured in the SDP, + // regardless of what RTX payload type mapping was negotiated in the SDP. + // TODO(brandtr): Update this comment when we have removed the RED/RTX + // send-side workaround, i.e., when we do not support enabling RED without + // enabling ULPFEC. + virtual void SetUlpfecConfig(int red_payload_type, + int ulpfec_payload_type) = 0; + + // Set FEC rates, max frames before FEC is sent, and type of FEC masks. + // Returns false on failure. + virtual bool SetFecParameters(const FecProtectionParams& delta_params, + const FecProtectionParams& key_params) = 0; + + // Deprecated version of member function above. + RTC_DEPRECATED + int32_t SetFecParameters(const FecProtectionParams* delta_params, + const FecProtectionParams* key_params); + + // Set method for requestion a new key frame. + // Returns -1 on failure else 0. + virtual int32_t SetKeyFrameRequestMethod(KeyFrameRequestMethod method) = 0; + + // Sends a request for a keyframe. + // Returns -1 on failure else 0. + virtual int32_t RequestKeyFrame() = 0; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.cc new file mode 100644 index 0000000000..af3714b25e --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.cc @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/include/rtp_rtcp_defines.h" + +namespace webrtc { + +PayloadUnion::PayloadUnion(const AudioPayload& payload) + : audio_payload_(payload) {} +PayloadUnion::PayloadUnion(const VideoPayload& payload) + : video_payload_(payload) {} +PayloadUnion::PayloadUnion(const PayloadUnion&) = default; +PayloadUnion::PayloadUnion(PayloadUnion&&) = default; +PayloadUnion::~PayloadUnion() = default; + +PayloadUnion& PayloadUnion::operator=(const PayloadUnion&) = default; +PayloadUnion& PayloadUnion::operator=(PayloadUnion&&) = default; + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h new file mode 100644 index 0000000000..f951a7df04 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h @@ -0,0 +1,508 @@ +/* + * 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 MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_DEFINES_H_ +#define MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_DEFINES_H_ + +#include <stddef.h> +#include <list> +#include <vector> + +#include "api/audio_codecs/audio_format.h" +#include "common_types.h" // NOLINT(build/include) +#include "modules/include/module_common_types.h" +#include "rtc_base/deprecation.h" +#include "system_wrappers/include/clock.h" +#include "typedefs.h" // NOLINT(build/include) + +#define RTCP_CNAME_SIZE 256 // RFC 3550 page 44, including null termination +#define IP_PACKET_SIZE 1500 // we assume ethernet +#define MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS 10 + +namespace webrtc { +namespace rtcp { +class TransportFeedback; +} + +const int kVideoPayloadTypeFrequency = 90000; +// TODO(solenberg): RTP time stamp rate for RTCP is fixed at 8k, this is legacy +// and should be fixed. +// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6458 +const int kBogusRtpRateForAudioRtcp = 8000; + +// Minimum RTP header size in bytes. +const uint8_t kRtpHeaderSize = 12; + +struct AudioPayload { + SdpAudioFormat format; + uint32_t rate; +}; + +struct VideoPayload { + RtpVideoCodecTypes videoCodecType; + // The H264 profile only matters if videoCodecType == kRtpVideoH264. + H264::Profile h264_profile; +}; + +class PayloadUnion { + public: + explicit PayloadUnion(const AudioPayload& payload); + explicit PayloadUnion(const VideoPayload& payload); + PayloadUnion(const PayloadUnion&); + PayloadUnion(PayloadUnion&&); + ~PayloadUnion(); + + PayloadUnion& operator=(const PayloadUnion&); + PayloadUnion& operator=(PayloadUnion&&); + + bool is_audio() const { return audio_payload_.has_value(); } + bool is_video() const { return video_payload_.has_value(); } + const AudioPayload& audio_payload() const { + RTC_DCHECK(audio_payload_); + return *audio_payload_; + } + const VideoPayload& video_payload() const { + RTC_DCHECK(video_payload_); + return *video_payload_; + } + AudioPayload& audio_payload() { + RTC_DCHECK(audio_payload_); + return *audio_payload_; + } + VideoPayload& video_payload() { + RTC_DCHECK(video_payload_); + return *video_payload_; + } + + private: + rtc::Optional<AudioPayload> audio_payload_; + rtc::Optional<VideoPayload> video_payload_; +}; + +enum RTPAliveType { kRtpDead = 0, kRtpNoRtp = 1, kRtpAlive = 2 }; + +enum ProtectionType { + kUnprotectedPacket, + kProtectedPacket +}; + +enum StorageType { + kDontRetransmit, + kAllowRetransmission +}; + +enum RTPExtensionType { + kRtpExtensionNone, + kRtpExtensionTransmissionTimeOffset, + kRtpExtensionAudioLevel, + kRtpExtensionAbsoluteSendTime, + kRtpExtensionVideoRotation, + kRtpExtensionTransportSequenceNumber, + kRtpExtensionPlayoutDelay, + kRtpExtensionVideoContentType, + kRtpExtensionVideoTiming, + kRtpExtensionRtpStreamId, + kRtpExtensionRepairedRtpStreamId, + kRtpExtensionMid, + kRtpExtensionCsrcAudioLevel, + kRtpExtensionNumberOfExtensions // Must be the last entity in the enum. +}; + +enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 }; + +// TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up. +enum RTCPPacketType : uint32_t { + kRtcpReport = 0x0001, + kRtcpSr = 0x0002, + kRtcpRr = 0x0004, + kRtcpSdes = 0x0008, + kRtcpBye = 0x0010, + kRtcpPli = 0x0020, + kRtcpNack = 0x0040, + kRtcpFir = 0x0080, + kRtcpTmmbr = 0x0100, + kRtcpTmmbn = 0x0200, + kRtcpSrReq = 0x0400, + kRtcpXrVoipMetric = 0x0800, + kRtcpApp = 0x1000, + kRtcpRemb = 0x10000, + kRtcpTransmissionTimeOffset = 0x20000, + kRtcpXrReceiverReferenceTime = 0x40000, + kRtcpXrDlrrReportBlock = 0x80000, + kRtcpTransportFeedback = 0x100000, + kRtcpXrTargetBitrate = 0x200000 +}; + +enum KeyFrameRequestMethod { kKeyFrameReqPliRtcp, kKeyFrameReqFirRtcp }; + +enum RtpRtcpPacketType { kPacketRtp = 0, kPacketKeepAlive = 1 }; + +// kConditionallyRetransmitHigherLayers allows retransmission of video frames +// in higher layers if either the last frame in that layer was too far back in +// time, or if we estimate that a new frame will be available in a lower layer +// in a shorter time than it would take to request and receive a retransmission. +enum RetransmissionMode : uint8_t { + kRetransmitOff = 0x0, + kRetransmitFECPackets = 0x1, + kRetransmitBaseLayer = 0x2, + kRetransmitHigherLayers = 0x4, + kConditionallyRetransmitHigherLayers = 0x8, + kRetransmitAllPackets = 0xFF +}; + +enum RtxMode { + kRtxOff = 0x0, + kRtxRetransmitted = 0x1, // Only send retransmissions over RTX. + kRtxRedundantPayloads = 0x2 // Preventively send redundant payloads + // instead of padding. +}; + +const size_t kRtxHeaderSize = 2; + +struct RTCPReportBlock { + RTCPReportBlock() + : sender_ssrc(0), + source_ssrc(0), + fraction_lost(0), + packets_lost(0), + extended_highest_sequence_number(0), + jitter(0), + last_sender_report_timestamp(0), + delay_since_last_sender_report(0) {} + + RTCPReportBlock(uint32_t sender_ssrc, + uint32_t source_ssrc, + uint8_t fraction_lost, + uint32_t packets_lost, + uint32_t extended_highest_sequence_number, + uint32_t jitter, + uint32_t last_sender_report_timestamp, + uint32_t delay_since_last_sender_report) + : sender_ssrc(sender_ssrc), + source_ssrc(source_ssrc), + fraction_lost(fraction_lost), + packets_lost(packets_lost), + extended_highest_sequence_number(extended_highest_sequence_number), + jitter(jitter), + last_sender_report_timestamp(last_sender_report_timestamp), + delay_since_last_sender_report(delay_since_last_sender_report) {} + + // Fields as described by RFC 3550 6.4.2. + uint32_t sender_ssrc; // SSRC of sender of this report. + uint32_t source_ssrc; // SSRC of the RTP packet sender. + uint8_t fraction_lost; + uint32_t packets_lost; // 24 bits valid. + uint32_t extended_highest_sequence_number; + uint32_t jitter; + uint32_t last_sender_report_timestamp; + uint32_t delay_since_last_sender_report; +}; + +typedef std::list<RTCPReportBlock> ReportBlockList; + +struct RtpState { + RtpState() + : sequence_number(0), + start_timestamp(0), + timestamp(0), + capture_time_ms(-1), + last_timestamp_time_ms(-1), + media_has_been_sent(false) {} + uint16_t sequence_number; + uint32_t start_timestamp; + uint32_t timestamp; + int64_t capture_time_ms; + int64_t last_timestamp_time_ms; + bool media_has_been_sent; +}; + +class RtpData { + public: + virtual ~RtpData() {} + + virtual int32_t OnReceivedPayloadData(const uint8_t* payload_data, + size_t payload_size, + const WebRtcRTPHeader* rtp_header) = 0; +}; + +// Callback interface for packets recovered by FlexFEC or ULPFEC. In +// the FlexFEC case, the implementation should be able to demultiplex +// the recovered RTP packets based on SSRC. +class RecoveredPacketReceiver { + public: + virtual void OnRecoveredPacket(const uint8_t* packet, size_t length) = 0; + + protected: + virtual ~RecoveredPacketReceiver() = default; +}; + +class RtpFeedback { + public: + virtual ~RtpFeedback() {} + + // Receiving payload change or SSRC change. (return success!) + /* + * channels - number of channels in codec (1 = mono, 2 = stereo) + */ + virtual int32_t OnInitializeDecoder(int payload_type, + const SdpAudioFormat& audio_format, + uint32_t rate) = 0; + + virtual void OnIncomingSSRCChanged(uint32_t ssrc) = 0; + + virtual void OnIncomingCSRCChanged(uint32_t csrc, bool added) = 0; +}; + +class RtcpIntraFrameObserver { + public: + virtual void OnReceivedIntraFrameRequest(uint32_t ssrc) = 0; + + RTC_DEPRECATED virtual void OnReceivedSLI(uint32_t ssrc, + uint8_t picture_id) {} + + RTC_DEPRECATED virtual void OnReceivedRPSI(uint32_t ssrc, + uint64_t picture_id) {} + + virtual ~RtcpIntraFrameObserver() {} +}; + +class RtcpBandwidthObserver { + public: + // REMB or TMMBR + virtual void OnReceivedEstimatedBitrate(uint32_t bitrate) = 0; + + virtual void OnReceivedRtcpReceiverReport( + const ReportBlockList& report_blocks, + int64_t rtt, + int64_t now_ms) = 0; + + virtual ~RtcpBandwidthObserver() {} +}; + +class RtcpEventObserver { + public: + virtual void OnRtcpBye() = 0; + virtual void OnRtcpTimeout() = 0; + + virtual ~RtcpEventObserver() {} +}; + +struct PacketFeedback { + PacketFeedback(int64_t arrival_time_ms, uint16_t sequence_number) + : PacketFeedback(-1, + arrival_time_ms, + -1, + sequence_number, + 0, + 0, + 0, + PacedPacketInfo()) {} + + PacketFeedback(int64_t arrival_time_ms, + int64_t send_time_ms, + uint16_t sequence_number, + size_t payload_size, + const PacedPacketInfo& pacing_info) + : PacketFeedback(-1, + arrival_time_ms, + send_time_ms, + sequence_number, + payload_size, + 0, + 0, + pacing_info) {} + + PacketFeedback(int64_t creation_time_ms, + uint16_t sequence_number, + size_t payload_size, + uint16_t local_net_id, + uint16_t remote_net_id, + const PacedPacketInfo& pacing_info) + : PacketFeedback(creation_time_ms, + -1, + -1, + sequence_number, + payload_size, + local_net_id, + remote_net_id, + pacing_info) {} + + PacketFeedback(int64_t creation_time_ms, + int64_t arrival_time_ms, + int64_t send_time_ms, + uint16_t sequence_number, + size_t payload_size, + uint16_t local_net_id, + uint16_t remote_net_id, + const PacedPacketInfo& pacing_info) + : creation_time_ms(creation_time_ms), + arrival_time_ms(arrival_time_ms), + send_time_ms(send_time_ms), + sequence_number(sequence_number), + payload_size(payload_size), + local_net_id(local_net_id), + remote_net_id(remote_net_id), + pacing_info(pacing_info) {} + + static constexpr int kNotAProbe = -1; + static constexpr int64_t kNotReceived = -1; + + // NOTE! The variable |creation_time_ms| is not used when testing equality. + // This is due to |creation_time_ms| only being used by SendTimeHistory + // for book-keeping, and is of no interest outside that class. + // TODO(philipel): Remove |creation_time_ms| from PacketFeedback when cleaning + // up SendTimeHistory. + bool operator==(const PacketFeedback& rhs) const { + return arrival_time_ms == rhs.arrival_time_ms && + send_time_ms == rhs.send_time_ms && + sequence_number == rhs.sequence_number && + payload_size == rhs.payload_size && pacing_info == rhs.pacing_info; + } + + // Time corresponding to when this object was created. + int64_t creation_time_ms; + // Time corresponding to when the packet was received. Timestamped with the + // receiver's clock. For unreceived packet, the sentinel value kNotReceived + // is used. + int64_t arrival_time_ms; + // Time corresponding to when the packet was sent, timestamped with the + // sender's clock. + int64_t send_time_ms; + // Packet identifier, incremented with 1 for every packet generated by the + // sender. + uint16_t sequence_number; + // Size of the packet excluding RTP headers. + size_t payload_size; + // The network route ids that this packet is associated with. + uint16_t local_net_id; + uint16_t remote_net_id; + // Pacing information about this packet. + PacedPacketInfo pacing_info; +}; + +class PacketFeedbackComparator { + public: + inline bool operator()(const PacketFeedback& lhs, const PacketFeedback& rhs) { + if (lhs.arrival_time_ms != rhs.arrival_time_ms) + return lhs.arrival_time_ms < rhs.arrival_time_ms; + if (lhs.send_time_ms != rhs.send_time_ms) + return lhs.send_time_ms < rhs.send_time_ms; + return lhs.sequence_number < rhs.sequence_number; + } +}; + +class TransportFeedbackObserver { + public: + TransportFeedbackObserver() {} + virtual ~TransportFeedbackObserver() {} + + // Note: Transport-wide sequence number as sequence number. + virtual void AddPacket(uint32_t ssrc, + uint16_t sequence_number, + size_t length, + const PacedPacketInfo& pacing_info) = 0; + + virtual void OnTransportFeedback(const rtcp::TransportFeedback& feedback) = 0; + + virtual std::vector<PacketFeedback> GetTransportFeedbackVector() const = 0; +}; + +class PacketFeedbackObserver { + public: + virtual ~PacketFeedbackObserver() = default; + + virtual void OnPacketAdded(uint32_t ssrc, uint16_t seq_num) = 0; + virtual void OnPacketFeedbackVector( + const std::vector<PacketFeedback>& packet_feedback_vector) = 0; +}; + +class RtcpRttStats { + public: + virtual void OnRttUpdate(int64_t rtt) = 0; + + virtual int64_t LastProcessedRtt() const = 0; + + virtual ~RtcpRttStats() {} +}; + +// Null object version of RtpFeedback. +class NullRtpFeedback : public RtpFeedback { + public: + ~NullRtpFeedback() override {} + + int32_t OnInitializeDecoder(int payload_type, + const SdpAudioFormat& audio_format, + uint32_t rate) override; + + void OnIncomingSSRCChanged(uint32_t ssrc) override {} + void OnIncomingCSRCChanged(uint32_t csrc, bool added) override {} +}; + +inline int32_t NullRtpFeedback::OnInitializeDecoder( + int payload_type, + const SdpAudioFormat& audio_format, + uint32_t rate) { + return 0; +} + +// Statistics about packet loss for a single directional connection. All values +// are totals since the connection initiated. +struct RtpPacketLossStats { + // The number of packets lost in events where no adjacent packets were also + // lost. + uint64_t single_packet_loss_count; + // The number of events in which more than one adjacent packet was lost. + uint64_t multiple_packet_loss_event_count; + // The number of packets lost in events where more than one adjacent packet + // was lost. + uint64_t multiple_packet_loss_packet_count; +}; + +class RtpPacketSender { + public: + RtpPacketSender() {} + virtual ~RtpPacketSender() {} + + enum Priority { + kHighPriority = 0, // Pass through; will be sent immediately. + kNormalPriority = 2, // Put in back of the line. + kLowPriority = 3, // Put in back of the low priority line. + }; + // Low priority packets are mixed with the normal priority packets + // while we are paused. + + // Returns true if we send the packet now, else it will add the packet + // information to the queue and call TimeToSendPacket when it's time to send. + virtual void InsertPacket(Priority priority, + uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + size_t bytes, + bool retransmission) = 0; + + // Currently audio traffic is not accounted by pacer and passed through. + // With the introduction of audio BWE audio traffic will be accounted for + // the pacer budget calculation. The audio traffic still will be injected + // at high priority. + // TODO(alexnarest): Make it pure virtual after rtp_sender_unittest will be + // updated to support it + virtual void SetAccountForAudioPackets(bool account_for_audio) {} +}; + +class TransportSequenceNumberAllocator { + public: + TransportSequenceNumberAllocator() {} + virtual ~TransportSequenceNumberAllocator() {} + + virtual uint16_t AllocateSequenceNumber() = 0; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_DEFINES_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/ulpfec_receiver.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/ulpfec_receiver.h new file mode 100644 index 0000000000..6ea8496f83 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/ulpfec_receiver.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef MODULES_RTP_RTCP_INCLUDE_ULPFEC_RECEIVER_H_ +#define MODULES_RTP_RTCP_INCLUDE_ULPFEC_RECEIVER_H_ + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +struct FecPacketCounter { + FecPacketCounter() + : num_packets(0), + num_fec_packets(0), + num_recovered_packets(0), + first_packet_time_ms(-1) {} + + size_t num_packets; // Number of received packets. + size_t num_fec_packets; // Number of received FEC packets. + size_t num_recovered_packets; // Number of recovered media packets using FEC. + int64_t first_packet_time_ms; // Time when first packet is received. +}; + +class UlpfecReceiver { + public: + static UlpfecReceiver* Create(uint32_t ssrc, + RecoveredPacketReceiver* callback); + + virtual ~UlpfecReceiver() {} + + // Takes a RED packet, strips the RED header, and adds the resulting + // "virtual" RTP packet(s) into the internal buffer. + // + // TODO(brandtr): Set |ulpfec_payload_type| during constructor call, + // rather than as a parameter here. + virtual int32_t AddReceivedRedPacket(const RTPHeader& rtp_header, + const uint8_t* incoming_rtp_packet, + size_t packet_length, + uint8_t ulpfec_payload_type) = 0; + + // Sends the received packets to the FEC and returns all packets + // (both original media and recovered) through the callback. + virtual int32_t ProcessReceivedFec() = 0; + + // Returns a counter describing the added and recovered packets. + virtual FecPacketCounter GetPacketCounter() const = 0; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_INCLUDE_ULPFEC_RECEIVER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h new file mode 100644 index 0000000000..501c5c3298 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_MOCKS_MOCK_RECOVERED_PACKET_RECEIVER_H_ +#define MODULES_RTP_RTCP_MOCKS_MOCK_RECOVERED_PACKET_RECEIVER_H_ + +#include "modules/rtp_rtcp/include/flexfec_receiver.h" +#include "rtc_base/basictypes.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockRecoveredPacketReceiver : public RecoveredPacketReceiver { + public: + MOCK_METHOD2(OnRecoveredPacket, void(const uint8_t* packet, size_t length)); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_MOCKS_MOCK_RECOVERED_PACKET_RECEIVER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h new file mode 100644 index 0000000000..8f2bb6e1e1 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_MOCKS_MOCK_RTCP_RTT_STATS_H_ +#define MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_RTT_STATS_H_ + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockRtcpRttStats : public RtcpRttStats { + public: + MOCK_METHOD1(OnRttUpdate, void(int64_t rtt)); + MOCK_CONST_METHOD0(LastProcessedRtt, int64_t()); +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_RTT_STATS_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h new file mode 100644 index 0000000000..f1c3842906 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -0,0 +1,216 @@ +/* + * 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 MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_ +#define MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_ + +#include <set> +#include <utility> +#include <vector> + +#include "api/optional.h" +#include "modules/include/module.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "rtc_base/checks.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockRtpData : public RtpData { + public: + MOCK_METHOD3(OnReceivedPayloadData, + int32_t(const uint8_t* payload_data, + size_t payload_size, + const WebRtcRTPHeader* rtp_header)); +}; + +class MockRtpRtcp : public RtpRtcp { + public: + MOCK_METHOD1(RegisterDefaultModule, int32_t(RtpRtcp* module)); + MOCK_METHOD0(DeRegisterDefaultModule, int32_t()); + MOCK_METHOD0(DefaultModuleRegistered, bool()); + MOCK_METHOD0(NumberChildModules, uint32_t()); + MOCK_METHOD1(RegisterSyncModule, int32_t(RtpRtcp* module)); + MOCK_METHOD0(DeRegisterSyncModule, int32_t()); + MOCK_METHOD2(IncomingRtcpPacket, + void(const uint8_t* incoming_packet, size_t packet_length)); + MOCK_METHOD1(SetRemoteSSRC, void(uint32_t ssrc)); + MOCK_METHOD4(IncomingAudioNTP, + int32_t(uint32_t audio_received_ntp_secs, + uint32_t audio_received_ntp_frac, + uint32_t audio_rtcp_arrival_time_secs, + uint32_t audio_rtcp_arrival_time_frac)); + MOCK_METHOD0(InitSender, int32_t()); + MOCK_METHOD1(RegisterSendTransport, int32_t(Transport* outgoing_transport)); + MOCK_METHOD1(SetMaxRtpPacketSize, void(size_t size)); + MOCK_METHOD1(SetTransportOverhead, void(int transport_overhead_per_packet)); + MOCK_CONST_METHOD0(MaxRtpPacketSize, size_t()); + MOCK_METHOD1(RegisterSendPayload, int32_t(const CodecInst& voice_codec)); + MOCK_METHOD1(RegisterSendPayload, int32_t(const VideoCodec& video_codec)); + MOCK_METHOD2(RegisterVideoSendPayload, + void(int payload_type, const char* payload_name)); + MOCK_METHOD1(DeRegisterSendPayload, int32_t(int8_t payload_type)); + MOCK_METHOD2(RegisterSendRtpHeaderExtension, + int32_t(RTPExtensionType type, uint8_t id)); + MOCK_METHOD1(DeregisterSendRtpHeaderExtension, + int32_t(RTPExtensionType type)); + MOCK_CONST_METHOD0(HasBweExtensions, bool()); + MOCK_CONST_METHOD0(StartTimestamp, uint32_t()); + MOCK_METHOD1(SetStartTimestamp, void(uint32_t timestamp)); + MOCK_CONST_METHOD0(SequenceNumber, uint16_t()); + MOCK_METHOD1(SetSequenceNumber, void(uint16_t seq)); + MOCK_METHOD1(SetRtpState, void(const RtpState& rtp_state)); + MOCK_METHOD1(SetRtxState, void(const RtpState& rtp_state)); + MOCK_CONST_METHOD0(GetRtpState, RtpState()); + MOCK_CONST_METHOD0(GetRtxState, RtpState()); + MOCK_CONST_METHOD0(SSRC, uint32_t()); + MOCK_METHOD1(SetSSRC, void(uint32_t ssrc)); + MOCK_METHOD1(SetRID, int32_t(const char *rid)); + MOCK_METHOD1(SetMID, int32_t(const char *mid)); + MOCK_CONST_METHOD1(CSRCs, int32_t(uint32_t csrcs[kRtpCsrcSize])); + MOCK_METHOD1(SetCsrcs, void(const std::vector<uint32_t>& csrcs)); + MOCK_METHOD1(SetCSRCStatus, int32_t(bool include)); + MOCK_METHOD1(SetRtxSendStatus, void(int modes)); + MOCK_CONST_METHOD0(RtxSendStatus, int()); + MOCK_METHOD1(SetRtxSsrc, void(uint32_t)); + MOCK_METHOD2(SetRtxSendPayloadType, void(int, int)); + MOCK_CONST_METHOD0(FlexfecSsrc, rtc::Optional<uint32_t>()); + MOCK_CONST_METHOD0(RtxSendPayloadType, std::pair<int, int>()); + MOCK_METHOD1(SetSendingStatus, int32_t(bool sending)); + MOCK_CONST_METHOD0(Sending, bool()); + MOCK_METHOD1(SetSendingMediaStatus, void(bool sending)); + MOCK_CONST_METHOD0(SendingMedia, bool()); + MOCK_CONST_METHOD4(BitrateSent, + void(uint32_t* total_rate, + uint32_t* video_rate, + uint32_t* fec_rate, + uint32_t* nack_rate)); + MOCK_METHOD1(RegisterVideoBitrateObserver, void(BitrateStatisticsObserver*)); + MOCK_CONST_METHOD0(GetVideoBitrateObserver, BitrateStatisticsObserver*(void)); + MOCK_CONST_METHOD1(EstimatedReceiveBandwidth, + int(uint32_t* available_bandwidth)); + MOCK_METHOD9(SendOutgoingData, + bool(FrameType frame_type, + int8_t payload_type, + uint32_t timestamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* rtp_video_header, + uint32_t* frame_id_out)); + MOCK_METHOD5(TimeToSendPacket, + bool(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission, + const PacedPacketInfo& pacing_info)); + MOCK_METHOD2(TimeToSendPadding, + size_t(size_t bytes, const PacedPacketInfo& pacing_info)); + MOCK_METHOD2(RegisterRtcpObservers, + void(RtcpIntraFrameObserver* intra_frame_callback, + RtcpBandwidthObserver* bandwidth_callback)); + MOCK_CONST_METHOD0(RTCP, RtcpMode()); + MOCK_METHOD1(SetRTCPStatus, void(RtcpMode method)); + MOCK_METHOD1(SetCNAME, int32_t(const char cname[RTCP_CNAME_SIZE])); + MOCK_CONST_METHOD2(RemoteCNAME, + int32_t(uint32_t remote_ssrc, + char cname[RTCP_CNAME_SIZE])); + MOCK_CONST_METHOD5(RemoteNTP, + int32_t(uint32_t* received_ntp_secs, + uint32_t* received_ntp_frac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp)); + MOCK_METHOD2(AddMixedCNAME, + int32_t(uint32_t ssrc, const char cname[RTCP_CNAME_SIZE])); + MOCK_METHOD1(RemoveMixedCNAME, int32_t(uint32_t ssrc)); + MOCK_CONST_METHOD5(RTT, + int32_t(uint32_t remote_ssrc, + int64_t* rtt, + int64_t* avg_rtt, + int64_t* min_rtt, + int64_t* max_rtt)); + MOCK_METHOD1(SendRTCP, int32_t(RTCPPacketType packet_type)); + MOCK_METHOD1(SendCompoundRTCP, + int32_t(const std::set<RTCPPacketType>& packet_types)); + MOCK_CONST_METHOD2(DataCountersRTP, + int32_t(size_t* bytes_sent, uint32_t* packets_sent)); + MOCK_CONST_METHOD2(GetSendStreamDataCounters, + void(StreamDataCounters*, StreamDataCounters*)); + MOCK_CONST_METHOD3(GetRtpPacketLossStats, + void(bool, uint32_t, struct RtpPacketLossStats*)); + MOCK_CONST_METHOD3(RemoteRTCPSenderInfo, + void(uint32_t* packet_count, uint32_t* octet_count, + NtpTime* ntp_timestamp)); + MOCK_CONST_METHOD1(RemoteRTCPStat, + int32_t(std::vector<RTCPReportBlock>* receive_blocks)); + MOCK_METHOD4(SetRTCPApplicationSpecificData, + int32_t(uint8_t sub_type, + uint32_t name, + const uint8_t* data, + uint16_t length)); + MOCK_METHOD1(SetRTCPVoIPMetrics, int32_t(const RTCPVoIPMetric* voip_metric)); + MOCK_METHOD1(SetRtcpXrRrtrStatus, void(bool enable)); + MOCK_CONST_METHOD0(RtcpXrRrtrStatus, bool()); + MOCK_METHOD2(SetRemb, + void(uint32_t bitrate, const std::vector<uint32_t>& ssrcs)); + MOCK_METHOD0(UnsetRemb, void()); + MOCK_CONST_METHOD0(TMMBR, bool()); + MOCK_METHOD1(SetTMMBRStatus, void(bool enable)); + MOCK_METHOD1(OnBandwidthEstimateUpdate, void(uint16_t bandwidth_kbit)); + MOCK_CONST_METHOD0(SelectiveRetransmissions, int()); + MOCK_METHOD1(SetSelectiveRetransmissions, int(uint8_t settings)); + MOCK_METHOD2(SendNACK, int32_t(const uint16_t* nack_list, uint16_t size)); + MOCK_METHOD1(SendNack, void(const std::vector<uint16_t>& sequence_numbers)); + MOCK_METHOD2(SetStorePacketsStatus, + void(bool enable, uint16_t number_to_store)); + MOCK_CONST_METHOD0(StorePackets, bool()); + MOCK_METHOD1(RegisterRtcpStatisticsCallback, void(RtcpStatisticsCallback*)); + MOCK_METHOD0(GetRtcpStatisticsCallback, RtcpStatisticsCallback*()); + MOCK_METHOD1(SendFeedbackPacket, bool(const rtcp::TransportFeedback& packet)); + MOCK_METHOD3(SendTelephoneEventOutband, + int32_t(uint8_t key, uint16_t time_ms, uint8_t level)); + MOCK_METHOD1(SetSendREDPayloadType, int32_t(int8_t payload_type)); + MOCK_CONST_METHOD1(SendREDPayloadType, int32_t(int8_t* payload_type)); + MOCK_METHOD2(SetRTPAudioLevelIndicationStatus, + int32_t(bool enable, uint8_t id)); + MOCK_METHOD1(SetAudioLevel, int32_t(uint8_t level_dbov)); + MOCK_METHOD1(SetTargetSendBitrate, void(uint32_t bitrate_bps)); + MOCK_METHOD2(SetUlpfecConfig, + void(int red_payload_type, int fec_payload_type)); + MOCK_METHOD2(SetFecParameters, + bool(const FecProtectionParams& delta_params, + const FecProtectionParams& key_params)); + MOCK_METHOD1(SetKeyFrameRequestMethod, int32_t(KeyFrameRequestMethod method)); + MOCK_METHOD0(RequestKeyFrame, int32_t()); + MOCK_METHOD0(Process, void()); + MOCK_METHOD1(RegisterSendFrameCountObserver, void(FrameCountObserver*)); + MOCK_CONST_METHOD0(GetSendFrameCountObserver, FrameCountObserver*(void)); + MOCK_METHOD1(RegisterSendChannelRtpStatisticsCallback, + void(StreamDataCountersCallback*)); + MOCK_CONST_METHOD0(GetSendChannelRtpStatisticsCallback, + StreamDataCountersCallback*(void)); + MOCK_METHOD1(SetVideoBitrateAllocation, void(const BitrateAllocation&)); + // Members. + unsigned int remote_ssrc_; + + private: + // Mocking this method is currently not required and having a default + // implementation like MOCK_METHOD0(TimeUntilNextProcess, int64_t()) + // can be dangerous since it can cause a tight loop on a process thread. + virtual int64_t TimeUntilNextProcess() { return 0xffffffff; } +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_format_gn/moz.build b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_format_gn/moz.build new file mode 100644 index 0000000000..2dbab17030 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_format_gn/moz.build @@ -0,0 +1,260 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + + ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ### + ### DO NOT edit it by hand. ### + +COMPILE_FLAGS["OS_INCLUDES"] = [] +AllowCompilerWarnings() + +DEFINES["CHROMIUM_BUILD"] = True +DEFINES["V8_DEPRECATION_WARNINGS"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_RESTRICT_LOGGING"] = True + +FINAL_LIBRARY = "webrtc" + + +LOCAL_INCLUDES += [ + "!/ipc/ipdl/_ipdlheaders", + "/ipc/chromium/src", + "/ipc/glue", + "/media/libyuv/libyuv/include/", + "/third_party/libwebrtc/webrtc/", + "/third_party/libwebrtc/webrtc/common_video/include/" +] + +SOURCES += [ + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc" +] + +UNIFIED_SOURCES += [ + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.cc" +] + +if not CONFIG["MOZ_DEBUG"]: + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0" + DEFINES["NDEBUG"] = True + DEFINES["NVALGRIND"] = True + +if CONFIG["MOZ_DEBUG"] == "1": + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1" + DEFINES["WTF_USE_DYNAMIC_ANNOTATIONS"] = "1" + +if CONFIG["OS_TARGET"] == "Android": + + DEFINES["ANDROID"] = True + DEFINES["ANDROID_NDK_VERSION"] = "r12b" + DEFINES["DISABLE_NACL"] = True + DEFINES["HAVE_SYS_UIO_H"] = True + DEFINES["NO_TCMALLOC"] = True + DEFINES["USE_OPENSSL_CERTS"] = "1" + DEFINES["WEBRTC_ANDROID"] = True + DEFINES["WEBRTC_ANDROID_OPENSLES"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["__GNU_SOURCE"] = "1" + + OS_LIBS += [ + "log" + ] + +if CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["NO_TCMALLOC"] = True + DEFINES["WEBRTC_MAC"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORE"] = "0" + + OS_LIBS += [ + "-framework Foundation" + ] + +if CONFIG["OS_TARGET"] == "DragonFly": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "FreeBSD": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_NSS_CERTS"] = "1" + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + + OS_LIBS += [ + "rt" + ] + +if CONFIG["OS_TARGET"] == "NetBSD": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True + DEFINES["NOMINMAX"] = True + DEFINES["NO_TCMALLOC"] = True + DEFINES["NTDDI_VERSION"] = "0x0A000000" + DEFINES["PSAPI_VERSION"] = "1" + DEFINES["UNICODE"] = True + DEFINES["WEBRTC_WIN"] = True + DEFINES["WIN32"] = True + DEFINES["WIN32_LEAN_AND_MEAN"] = True + DEFINES["WINVER"] = "0x0A00" + DEFINES["_ATL_NO_OPENGL"] = True + DEFINES["_CRT_RAND_S"] = True + DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True + DEFINES["_CRT_SECURE_NO_WARNINGS"] = True + DEFINES["_HAS_EXCEPTIONS"] = "0" + DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True + DEFINES["_SECURE_ATL"] = True + DEFINES["_UNICODE"] = True + DEFINES["_USING_V110_SDK71_"] = True + DEFINES["_WIN32_WINNT"] = "0x0A00" + DEFINES["_WINDOWS"] = True + DEFINES["__STD_C"] = True + + OS_LIBS += [ + "winmm" + ] + +if CONFIG["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Android": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "DragonFly": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "FreeBSD": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "NetBSD": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["CR_XCODE_VERSION"] = "0120" + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["CR_XCODE_VERSION"] = "0920" + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "FreeBSD": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["DISABLE_NACL"] = True + DEFINES["NO_TCMALLOC"] = True + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "NetBSD": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "OpenBSD": + + CXXFLAGS += [ + "-msse2" + ] + +Library("rtp_rtcp_format_gn") diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_gn/moz.build b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_gn/moz.build new file mode 100644 index 0000000000..61ec3c4a34 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_gn/moz.build @@ -0,0 +1,265 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + + ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ### + ### DO NOT edit it by hand. ### + +COMPILE_FLAGS["OS_INCLUDES"] = [] +AllowCompilerWarnings() + +DEFINES["BWE_TEST_LOGGING_COMPILE_TIME_ENABLE"] = "0" +DEFINES["CHROMIUM_BUILD"] = True +DEFINES["V8_DEPRECATION_WARNINGS"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_RESTRICT_LOGGING"] = True + +FINAL_LIBRARY = "webrtc" + + +LOCAL_INCLUDES += [ + "!/ipc/ipdl/_ipdlheaders", + "/ipc/chromium/src", + "/ipc/glue", + "/media/libyuv/libyuv/include/", + "/third_party/libwebrtc/webrtc/", + "/third_party/libwebrtc/webrtc/common_video/include/" +] + +SOURCES += [ + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc" +] + +UNIFIED_SOURCES += [ + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_parser.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc", + "/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc" +] + +if not CONFIG["MOZ_DEBUG"]: + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0" + DEFINES["NDEBUG"] = True + DEFINES["NVALGRIND"] = True + +if CONFIG["MOZ_DEBUG"] == "1": + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1" + DEFINES["WTF_USE_DYNAMIC_ANNOTATIONS"] = "1" + +if CONFIG["OS_TARGET"] == "Android": + + DEFINES["ANDROID"] = True + DEFINES["ANDROID_NDK_VERSION"] = "r12b" + DEFINES["DISABLE_NACL"] = True + DEFINES["HAVE_SYS_UIO_H"] = True + DEFINES["NO_TCMALLOC"] = True + DEFINES["USE_OPENSSL_CERTS"] = "1" + DEFINES["WEBRTC_ANDROID"] = True + DEFINES["WEBRTC_ANDROID_OPENSLES"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["__GNU_SOURCE"] = "1" + + OS_LIBS += [ + "log" + ] + +if CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["NO_TCMALLOC"] = True + DEFINES["WEBRTC_MAC"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORE"] = "0" + + OS_LIBS += [ + "-framework Foundation" + ] + +if CONFIG["OS_TARGET"] == "DragonFly": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "FreeBSD": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_NSS_CERTS"] = "1" + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + + OS_LIBS += [ + "rt" + ] + +if CONFIG["OS_TARGET"] == "NetBSD": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + +if CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True + DEFINES["NOMINMAX"] = True + DEFINES["NO_TCMALLOC"] = True + DEFINES["NTDDI_VERSION"] = "0x0A000000" + DEFINES["PSAPI_VERSION"] = "1" + DEFINES["UNICODE"] = True + DEFINES["WEBRTC_WIN"] = True + DEFINES["WIN32"] = True + DEFINES["WIN32_LEAN_AND_MEAN"] = True + DEFINES["WINVER"] = "0x0A00" + DEFINES["_ATL_NO_OPENGL"] = True + DEFINES["_CRT_RAND_S"] = True + DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True + DEFINES["_CRT_SECURE_NO_WARNINGS"] = True + DEFINES["_HAS_EXCEPTIONS"] = "0" + DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True + DEFINES["_SECURE_ATL"] = True + DEFINES["_UNICODE"] = True + DEFINES["_USING_V110_SDK71_"] = True + DEFINES["_WIN32_WINNT"] = "0x0A00" + DEFINES["_WINDOWS"] = True + DEFINES["__STD_C"] = True + + OS_LIBS += [ + "winmm" + ] + +if CONFIG["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Android": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "DragonFly": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "FreeBSD": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "NetBSD": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if not CONFIG["MOZ_DEBUG"] and CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["_FORTIFY_SOURCE"] = "2" + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["CR_XCODE_VERSION"] = "0120" + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["CR_XCODE_VERSION"] = "0920" + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "FreeBSD": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["DISABLE_NACL"] = True + DEFINES["NO_TCMALLOC"] = True + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "NetBSD": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "OpenBSD": + + CXXFLAGS += [ + "-msse2" + ] + +Library("rtp_rtcp_gn") diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io.h new file mode 100644 index 0000000000..e482452b9f --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io.h @@ -0,0 +1,408 @@ +/* + * 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. + */ + +#ifndef MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ +#define MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ + + +// This file contains classes for reading and writing integer types from/to +// byte array representations. Signed/unsigned, partial (whole byte) sizes, +// and big/little endian byte order is all supported. +// +// Usage examples: +// +// uint8_t* buffer = ...; +// +// // Read an unsigned 4 byte integer in big endian format +// uint32_t val = ByteReader<uint32_t>::ReadBigEndian(buffer); +// +// // Read a signed 24-bit (3 byte) integer in little endian format +// int32_t val = ByteReader<int32_t, 3>::ReadLittle(buffer); +// +// // Write an unsigned 8 byte integer in little endian format +// ByteWriter<uint64_t>::WriteLittleEndian(buffer, val); +// +// Write an unsigned 40-bit (5 byte) integer in big endian format +// ByteWriter<uint64_t, 5>::WriteBigEndian(buffer, val); +// +// These classes are implemented as recursive templetizations, inteded to make +// it easy for the compiler to completely inline the reading/writing. + + +#include <limits> + +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +// According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three +// representations of signed integers allowed are two's complement, one's +// complement and sign/magnitude. We can detect which is used by looking at +// the two last bits of -1, which will be 11 in two's complement, 10 in one's +// complement and 01 in sign/magnitude. +// TODO(sprang): In the unlikely event that we actually need to support a +// platform that doesn't use two's complement, implement conversion to/from +// wire format. + +// Assume the if any one signed integer type is two's complement, then all +// other will be too. +static_assert( + (-1 & 0x03) == 0x03, + "Only two's complement representation of signed integers supported."); + +// Plain const char* won't work for static_assert, use #define instead. +#define kSizeErrorMsg "Byte size must be less than or equal to data type size." + +// Utility class for getting the unsigned equivalent of a signed type. +template <typename T> +struct UnsignedOf; + +// Class for reading integers from a sequence of bytes. +// T = type of integer, B = bytes to read, is_signed = true if signed integer. +// If is_signed is true and B < sizeof(T), sign extension might be needed. +template <typename T, + unsigned int B = sizeof(T), + bool is_signed = std::numeric_limits<T>::is_signed> +class ByteReader; + +// Specialization of ByteReader for unsigned types. +template <typename T, unsigned int B> +class ByteReader<T, B, false> { + public: + static T ReadBigEndian(const uint8_t* data) { + static_assert(B <= sizeof(T), kSizeErrorMsg); + return InternalReadBigEndian(data); + } + + static T ReadLittleEndian(const uint8_t* data) { + static_assert(B <= sizeof(T), kSizeErrorMsg); + return InternalReadLittleEndian(data); + } + + private: + static T InternalReadBigEndian(const uint8_t* data) { + T val(0); + for (unsigned int i = 0; i < B; ++i) + val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8); + return val; + } + + static T InternalReadLittleEndian(const uint8_t* data) { + T val(0); + for (unsigned int i = 0; i < B; ++i) + val |= static_cast<T>(data[i]) << (i * 8); + return val; + } +}; + +// Specialization of ByteReader for signed types. +template <typename T, unsigned int B> +class ByteReader<T, B, true> { + public: + typedef typename UnsignedOf<T>::Type U; + + static T ReadBigEndian(const uint8_t* data) { + U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data); + if (B < sizeof(T)) + unsigned_val = SignExtend(unsigned_val); + return ReinterpretAsSigned(unsigned_val); + } + + static T ReadLittleEndian(const uint8_t* data) { + U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data); + if (B < sizeof(T)) + unsigned_val = SignExtend(unsigned_val); + return ReinterpretAsSigned(unsigned_val); + } + + private: + // As a hack to avoid implementation-specific or undefined behavior when + // bit-shifting or casting signed integers, read as a signed equivalent + // instead and convert to signed. This is safe since we have asserted that + // two's complement for is used. + static T ReinterpretAsSigned(U unsigned_val) { + // An unsigned value with only the highest order bit set (ex 0x80). + const U kUnsignedHighestBitMask = + static_cast<U>(1) << ((sizeof(U) * 8) - 1); + // A signed value with only the highest bit set. Since this is two's + // complement form, we can use the min value from std::numeric_limits. + const T kSignedHighestBitMask = std::numeric_limits<T>::min(); + + T val; + if ((unsigned_val & kUnsignedHighestBitMask) != 0) { + // Casting is only safe when unsigned value can be represented in the + // signed target type, so mask out highest bit and mask it back manually. + val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask); + val |= kSignedHighestBitMask; + } else { + val = static_cast<T>(unsigned_val); + } + return val; + } + + // If number of bytes is less than native data type (eg 24 bit, in int32_t), + // and the most significant bit of the actual data is set, we must sign + // extend the remaining byte(s) with ones so that the correct negative + // number is retained. + // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B + static U SignExtend(const U val) { + const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8)); + if ((kMsb & 0x80) != 0) { + // Create a mask where all bits used by the B bytes are set to one, + // for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to + // (0xFF000000 in the example above) and add it to the input value. + // The "B % sizeof(T)" is a workaround to undefined values warnings for + // B == sizeof(T), in which case this code won't be called anyway. + const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1; + return ~kUsedBitsMask | val; + } + return val; + } +}; + +// Class for writing integers to a sequence of bytes +// T = type of integer, B = bytes to write +template <typename T, + unsigned int B = sizeof(T), + bool is_signed = std::numeric_limits<T>::is_signed> +class ByteWriter; + +// Specialization of ByteWriter for unsigned types. +template <typename T, unsigned int B> +class ByteWriter<T, B, false> { + public: + static void WriteBigEndian(uint8_t* data, T val) { + static_assert(B <= sizeof(T), kSizeErrorMsg); + for (unsigned int i = 0; i < B; ++i) { + data[i] = val >> ((B - 1 - i) * 8); + } + } + + static void WriteLittleEndian(uint8_t* data, T val) { + static_assert(B <= sizeof(T), kSizeErrorMsg); + for (unsigned int i = 0; i < B; ++i) { + data[i] = val >> (i * 8); + } + } +}; + +// Specialization of ByteWriter for signed types. +template <typename T, unsigned int B> +class ByteWriter<T, B, true> { + public: + typedef typename UnsignedOf<T>::Type U; + + static void WriteBigEndian(uint8_t* data, T val) { + ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val)); + } + + static void WriteLittleEndian(uint8_t* data, T val) { + ByteWriter<U, B, false>::WriteLittleEndian(data, + ReinterpretAsUnsigned(val)); + } + + private: + static U ReinterpretAsUnsigned(T val) { + // According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a + // conversion from signed to unsigned keeps the value if the new type can + // represent it, and otherwise adds one more than the max value of T until + // the value is in range. For two's complement, this fortunately means + // that the bit-wise value will be intact. Thus, since we have asserted that + // two's complement form is actually used, a simple cast is sufficient. + return static_cast<U>(val); + } +}; + +// ----- Below follows specializations of UnsignedOf utility class ----- + +template <> +struct UnsignedOf<int8_t> { + typedef uint8_t Type; +}; +template <> +struct UnsignedOf<int16_t> { + typedef uint16_t Type; +}; +template <> +struct UnsignedOf<int32_t> { + typedef uint32_t Type; +}; +template <> +struct UnsignedOf<int64_t> { + typedef uint64_t Type; +}; + +// ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } ----- + +// TODO(sprang): Check if these actually help or if generic cases will be +// unrolled to and optimized to similar performance. + +// Specializations for single bytes +template <typename T> +class ByteReader<T, 1, false> { + public: + static T ReadBigEndian(const uint8_t* data) { + static_assert(sizeof(T) == 1, kSizeErrorMsg); + return data[0]; + } + + static T ReadLittleEndian(const uint8_t* data) { + static_assert(sizeof(T) == 1, kSizeErrorMsg); + return data[0]; + } +}; + +template <typename T> +class ByteWriter<T, 1, false> { + public: + static void WriteBigEndian(uint8_t* data, T val) { + static_assert(sizeof(T) == 1, kSizeErrorMsg); + data[0] = val; + } + + static void WriteLittleEndian(uint8_t* data, T val) { + static_assert(sizeof(T) == 1, kSizeErrorMsg); + data[0] = val; + } +}; + +// Specializations for two byte words +template <typename T> +class ByteReader<T, 2, false> { + public: + static T ReadBigEndian(const uint8_t* data) { + static_assert(sizeof(T) >= 2, kSizeErrorMsg); + return (data[0] << 8) | data[1]; + } + + static T ReadLittleEndian(const uint8_t* data) { + static_assert(sizeof(T) >= 2, kSizeErrorMsg); + return data[0] | (data[1] << 8); + } +}; + +template <typename T> +class ByteWriter<T, 2, false> { + public: + static void WriteBigEndian(uint8_t* data, T val) { + static_assert(sizeof(T) >= 2, kSizeErrorMsg); + data[0] = val >> 8; + data[1] = val; + } + + static void WriteLittleEndian(uint8_t* data, T val) { + static_assert(sizeof(T) >= 2, kSizeErrorMsg); + data[0] = val; + data[1] = val >> 8; + } +}; + +// Specializations for four byte words. +template <typename T> +class ByteReader<T, 4, false> { + public: + static T ReadBigEndian(const uint8_t* data) { + static_assert(sizeof(T) >= 4, kSizeErrorMsg); + return (Get(data, 0) << 24) | (Get(data, 1) << 16) | (Get(data, 2) << 8) | + Get(data, 3); + } + + static T ReadLittleEndian(const uint8_t* data) { + static_assert(sizeof(T) >= 4, kSizeErrorMsg); + return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) | + (Get(data, 3) << 24); + } + + private: + inline static T Get(const uint8_t* data, unsigned int index) { + return static_cast<T>(data[index]); + } +}; + +// Specializations for four byte words. +template <typename T> +class ByteWriter<T, 4, false> { + public: + static void WriteBigEndian(uint8_t* data, T val) { + static_assert(sizeof(T) >= 4, kSizeErrorMsg); + data[0] = val >> 24; + data[1] = val >> 16; + data[2] = val >> 8; + data[3] = val; + } + + static void WriteLittleEndian(uint8_t* data, T val) { + static_assert(sizeof(T) >= 4, kSizeErrorMsg); + data[0] = val; + data[1] = val >> 8; + data[2] = val >> 16; + data[3] = val >> 24; + } +}; + +// Specializations for eight byte words. +template <typename T> +class ByteReader<T, 8, false> { + public: + static T ReadBigEndian(const uint8_t* data) { + static_assert(sizeof(T) >= 8, kSizeErrorMsg); + return + (Get(data, 0) << 56) | (Get(data, 1) << 48) | + (Get(data, 2) << 40) | (Get(data, 3) << 32) | + (Get(data, 4) << 24) | (Get(data, 5) << 16) | + (Get(data, 6) << 8) | Get(data, 7); + } + + static T ReadLittleEndian(const uint8_t* data) { + static_assert(sizeof(T) >= 8, kSizeErrorMsg); + return + Get(data, 0) | (Get(data, 1) << 8) | + (Get(data, 2) << 16) | (Get(data, 3) << 24) | + (Get(data, 4) << 32) | (Get(data, 5) << 40) | + (Get(data, 6) << 48) | (Get(data, 7) << 56); + } + + private: + inline static T Get(const uint8_t* data, unsigned int index) { + return static_cast<T>(data[index]); + } +}; + +template <typename T> +class ByteWriter<T, 8, false> { + public: + static void WriteBigEndian(uint8_t* data, T val) { + static_assert(sizeof(T) >= 8, kSizeErrorMsg); + data[0] = val >> 56; + data[1] = val >> 48; + data[2] = val >> 40; + data[3] = val >> 32; + data[4] = val >> 24; + data[5] = val >> 16; + data[6] = val >> 8; + data[7] = val; + } + + static void WriteLittleEndian(uint8_t* data, T val) { + static_assert(sizeof(T) >= 8, kSizeErrorMsg); + data[0] = val; + data[1] = val >> 8; + data[2] = val >> 16; + data[3] = val >> 24; + data[4] = val >> 32; + data[5] = val >> 40; + data[6] = val >> 48; + data[7] = val >> 56; + } +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io_unittest.cc new file mode 100644 index 0000000000..3931a04fe3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io_unittest.cc @@ -0,0 +1,272 @@ +/* + * 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 <limits> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +class ByteIoTest : public ::testing::Test { + protected: + ByteIoTest() {} + virtual ~ByteIoTest() {} + + enum { kAlignments = sizeof(uint64_t) - 1 }; + + // Method to create a test value that is not the same when byte reversed. + template <typename T> + T CreateTestValue(bool negative, uint8_t num_bytes) { + // Examples of output: + // T = int32_t, negative = false, num_bytes = 4: 0x00010203 + // T = int32_t, negative = true, num_bytes = 4: 0xFFFEFDFC + // T = int32_t, negative = false, num_bytes = 3: 0x000102 + // * T = int32_t, negative = true, num_bytes = 3: 0xFFFEFD + + T val = 0; + for (uint8_t i = 0; i != num_bytes; ++i) { + val = (val << 8) + (negative ? (0xFF - i) : (i + 1)); + } + + // This loop will create a sign extend mask if num_bytes if necessary. + // For the last example (marked * above), the number needs to be sign + // extended to be a valid int32_t. The sign extend mask is 0xFF000000. + // Comments for each step with this example below. + if (std::numeric_limits<T>::is_signed && negative && + num_bytes < sizeof(T)) { + // Start with mask = 0xFFFFFFFF. + T mask = static_cast<T>(-1); + // Create a temporary for the lowest byte (0x000000FF). + const T neg_byte = static_cast<T>(0xFF); + for (int i = 0; i < num_bytes; ++i) { + // And the inverse of the temporary and the mask: + // 0xFFFFFFFF & 0xFFFFFF00 = 0xFFFFFF00. + // 0xFFFFFF00 & 0xFFFF00FF = 0xFFFF0000. + // 0xFFFF0000 & 0xFF00FFFF = 0xFF000000. + mask &= ~(neg_byte << (i * 8)); + } + // Add the sign extension mask to the actual value. + val |= mask; + } + return val; + } + + // Populate byte buffer with value, in big endian format. + template <typename T> + void PopulateTestData(uint8_t* data, T value, int num_bytes, bool bigendian) { + if (bigendian) { + for (int i = 0; i < num_bytes; ++i) { + data[i] = (value >> ((num_bytes - i - 1) * 8)) & 0xFF; + } + } else { + for (int i = 0; i < num_bytes; ++i) { + data[i] = (value >> (i * 8)) & 0xFF; + } + } + } + + // Test reading big endian numbers. + // Template arguments: Type T, read method RM(buffer), B bytes of data. + template <typename T, T (*RM)(const uint8_t*), int B> + void TestRead(bool big_endian) { + // Test both for values that are positive and negative (if signed) + for (int neg = 0; neg < 2; ++neg) { + bool negative = neg > 0; + + // Write test value to byte buffer, in big endian format. + T test_value = CreateTestValue<T>(negative, B); + uint8_t bytes[B + kAlignments]; + + // Make one test for each alignment. + for (int i = 0; i < kAlignments; ++i) { + PopulateTestData(bytes + i, test_value, B, big_endian); + + // Check that test value is retrieved from buffer when used read method. + EXPECT_EQ(test_value, RM(bytes + i)); + } + } + } + + // Test writing big endian numbers. + // Template arguments: Type T, write method WM(buffer, value), B bytes of data + template <typename T, void (*WM)(uint8_t*, T), int B> + void TestWrite(bool big_endian) { + // Test both for values that are positive and negative (if signed). + for (int neg = 0; neg < 2; ++neg) { + bool negative = neg > 0; + + // Write test value to byte buffer, in big endian format. + T test_value = CreateTestValue<T>(negative, B); + uint8_t expected_bytes[B + kAlignments]; + uint8_t bytes[B + kAlignments]; + + // Make one test for each alignment. + for (int i = 0; i < kAlignments; ++i) { + PopulateTestData(expected_bytes + i, test_value, B, big_endian); + + // Zero initialize buffer and let WM populate it. + memset(bytes, 0, B + kAlignments); + WM(bytes + i, test_value); + + // Check that data produced by WM is big endian as expected. + for (int j = 0; j < B; ++j) { + EXPECT_EQ(expected_bytes[i + j], bytes[i + j]); + } + } + } + } +}; + +TEST_F(ByteIoTest, Test16UBitBigEndian) { + TestRead<uint16_t, ByteReader<uint16_t>::ReadBigEndian, + sizeof(uint16_t)>(true); + TestWrite<uint16_t, ByteWriter<uint16_t>::WriteBigEndian, + sizeof(uint16_t)>(true); +} + +TEST_F(ByteIoTest, Test24UBitBigEndian) { + TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadBigEndian, 3>(true); + TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteBigEndian, 3>(true); +} + +TEST_F(ByteIoTest, Test32UBitBigEndian) { + TestRead<uint32_t, ByteReader<uint32_t>::ReadBigEndian, + sizeof(uint32_t)>(true); + TestWrite<uint32_t, ByteWriter<uint32_t>::WriteBigEndian, + sizeof(uint32_t)>(true); +} + +TEST_F(ByteIoTest, Test64UBitBigEndian) { + TestRead<uint64_t, ByteReader<uint64_t>::ReadBigEndian, + sizeof(uint64_t)>(true); + TestWrite<uint64_t, ByteWriter<uint64_t>::WriteBigEndian, + sizeof(uint64_t)>(true); +} + +TEST_F(ByteIoTest, Test16SBitBigEndian) { + TestRead<int16_t, ByteReader<int16_t>::ReadBigEndian, + sizeof(int16_t)>(true); + TestWrite<int16_t, ByteWriter<int16_t>::WriteBigEndian, + sizeof(int16_t)>(true); +} + +TEST_F(ByteIoTest, Test24SBitBigEndian) { + TestRead<int32_t, ByteReader<int32_t, 3>::ReadBigEndian, 3>(true); + TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteBigEndian, 3>(true); +} + +TEST_F(ByteIoTest, Test32SBitBigEndian) { + TestRead<int32_t, ByteReader<int32_t>::ReadBigEndian, + sizeof(int32_t)>(true); + TestWrite<int32_t, ByteWriter<int32_t>::WriteBigEndian, + sizeof(int32_t)>(true); +} + +TEST_F(ByteIoTest, Test64SBitBigEndian) { + TestRead<int64_t, ByteReader<int64_t>::ReadBigEndian, + sizeof(int64_t)>(true); + TestWrite<int64_t, ByteWriter<int64_t>::WriteBigEndian, + sizeof(int64_t)>(true); +} + +TEST_F(ByteIoTest, Test16UBitLittleEndian) { + TestRead<uint16_t, ByteReader<uint16_t>::ReadLittleEndian, + sizeof(uint16_t)>(false); + TestWrite<uint16_t, ByteWriter<uint16_t>::WriteLittleEndian, + sizeof(uint16_t)>(false); +} + +TEST_F(ByteIoTest, Test24UBitLittleEndian) { + TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadLittleEndian, 3>(false); + TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteLittleEndian, 3>(false); +} + +TEST_F(ByteIoTest, Test32UBitLittleEndian) { + TestRead<uint32_t, ByteReader<uint32_t>::ReadLittleEndian, + sizeof(uint32_t)>(false); + TestWrite<uint32_t, ByteWriter<uint32_t>::WriteLittleEndian, + sizeof(uint32_t)>(false); +} + +TEST_F(ByteIoTest, Test64UBitLittleEndian) { + TestRead<uint64_t, ByteReader<uint64_t>::ReadLittleEndian, + sizeof(uint64_t)>(false); + TestWrite<uint64_t, ByteWriter<uint64_t>::WriteLittleEndian, + sizeof(uint64_t)>(false); +} + +TEST_F(ByteIoTest, Test16SBitLittleEndian) { + TestRead<int16_t, ByteReader<int16_t>::ReadLittleEndian, + sizeof(int16_t)>(false); + TestWrite<int16_t, ByteWriter<int16_t>::WriteLittleEndian, + sizeof(int16_t)>(false); +} + +TEST_F(ByteIoTest, Test24SBitLittleEndian) { + TestRead<int32_t, ByteReader<int32_t, 3>::ReadLittleEndian, 3>(false); + TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteLittleEndian, 3>(false); +} + +TEST_F(ByteIoTest, Test32SBitLittleEndian) { + TestRead<int32_t, ByteReader<int32_t>::ReadLittleEndian, + sizeof(int32_t)>(false); + TestWrite<int32_t, ByteWriter<int32_t>::WriteLittleEndian, + sizeof(int32_t)>(false); +} + +TEST_F(ByteIoTest, Test64SBitLittleEndian) { + TestRead<int64_t, ByteReader<int64_t>::ReadLittleEndian, + sizeof(int64_t)>(false); + TestWrite<int64_t, ByteWriter<int64_t>::WriteLittleEndian, + sizeof(int64_t)>(false); +} + +// Sets up a fixed byte array and converts N bytes from the array into a +// uint64_t. Verifies the value with hard-coded reference. +TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadBigEndian) { + uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}; + uint64_t value = ByteReader<uint64_t, 2>::ReadBigEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xFFEE), value); + value = ByteReader<uint64_t, 3>::ReadBigEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xFFEEDD), value); + value = ByteReader<uint64_t, 4>::ReadBigEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCC), value); + value = ByteReader<uint64_t, 5>::ReadBigEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBB), value); + value = ByteReader<uint64_t, 6>::ReadBigEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA), value); + value = ByteReader<uint64_t, 7>::ReadBigEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA99), value); + value = ByteReader<uint64_t, 8>::ReadBigEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA9988), value); +} + +// Same as above, but for little-endian reading. +TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadLittleEndian) { + uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}; + uint64_t value = ByteReader<uint64_t, 2>::ReadLittleEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xEEFF), value); + value = ByteReader<uint64_t, 3>::ReadLittleEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xDDEEFF), value); + value = ByteReader<uint64_t, 4>::ReadLittleEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xCCDDEEFF), value); + value = ByteReader<uint64_t, 5>::ReadLittleEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xBBCCDDEEFF), value); + value = ByteReader<uint64_t, 6>::ReadLittleEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0xAABBCCDDEEFF), value); + value = ByteReader<uint64_t, 7>::ReadLittleEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0x99AABBCCDDEEFF), value); + value = ByteReader<uint64_t, 8>::ReadLittleEndian(data); + EXPECT_EQ(static_cast<uint64_t>(0x8899AABBCCDDEEFF), value); +} +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.cc new file mode 100644 index 0000000000..86ddb105f9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 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/rtp_rtcp/source/dtmf_queue.h" + +namespace { +constexpr size_t kDtmfOutbandMax = 20; +} + +namespace webrtc { +DtmfQueue::DtmfQueue() {} + +DtmfQueue::~DtmfQueue() {} + +bool DtmfQueue::AddDtmf(const Event& event) { + rtc::CritScope lock(&dtmf_critsect_); + if (queue_.size() >= kDtmfOutbandMax) { + return false; + } + queue_.push_back(event); + return true; +} + +bool DtmfQueue::NextDtmf(Event* event) { + RTC_DCHECK(event); + rtc::CritScope lock(&dtmf_critsect_); + if (queue_.empty()) { + return false; + } + + *event = queue_.front(); + queue_.pop_front(); + return true; +} + +bool DtmfQueue::PendingDtmf() const { + rtc::CritScope lock(&dtmf_critsect_); + return !queue_.empty(); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.h new file mode 100644 index 0000000000..db70c97508 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 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_RTP_RTCP_SOURCE_DTMF_QUEUE_H_ +#define MODULES_RTP_RTCP_SOURCE_DTMF_QUEUE_H_ + +#include <list> + +#include "rtc_base/criticalsection.h" + +namespace webrtc { +class DtmfQueue { + public: + struct Event { + uint16_t duration_ms = 0; + uint8_t payload_type = 0; + uint8_t key = 0; + uint8_t level = 0; + }; + + DtmfQueue(); + ~DtmfQueue(); + + bool AddDtmf(const Event& event); + bool NextDtmf(Event* event); + bool PendingDtmf() const; + + private: + rtc::CriticalSection dtmf_critsect_; + std::list<Event> queue_; +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_DTMF_QUEUE_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_bursty.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_bursty.h new file mode 100644 index 0000000000..7fba7aa550 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_bursty.h @@ -0,0 +1,762 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_ +#define MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_ + +// This file contains a set of packets masks for the FEC code. The masks in +// this table are specifically designed to favor recovery of bursty/consecutive +// loss network conditions. The tradeoff is worse recovery for random losses. +// These packet masks are currently defined to protect up to 12 media packets. +// They have the following property: for any packet mask defined by the +// parameters (k,m), where k = number of media packets, m = number of FEC +// packets, all "consecutive" losses of size <= m are completely recoverable. +// By consecutive losses we mean consecutive with respect to the sequence +// number ordering of the list (media and FEC) of packets. The difference +// between these masks (|kFecMaskBursty|) and |kFecMaskRandom| type, defined +// in fec_private_tables.h, is more significant for longer codes +// (i.e., more packets/symbols in the code, so larger (k,m), i.e., k > 4, +// m > 3). + +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace fec_private_tables { + +const uint8_t kMaskBursty1_1[2] = { + 0x80, 0x00 +}; + +const uint8_t kMaskBursty2_1[2] = { + 0xc0, 0x00 +}; + +const uint8_t kMaskBursty2_2[4] = { + 0x80, 0x00, + 0xc0, 0x00 +}; + +const uint8_t kMaskBursty3_1[2] = { + 0xe0, 0x00 +}; + +const uint8_t kMaskBursty3_2[4] = { + 0xc0, 0x00, + 0xa0, 0x00 +}; + +const uint8_t kMaskBursty3_3[6] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00 +}; + +const uint8_t kMaskBursty4_1[2] = { + 0xf0, 0x00 +}; + +const uint8_t kMaskBursty4_2[4] = { + 0xa0, 0x00, + 0xd0, 0x00 +}; + +const uint8_t kMaskBursty4_3[6] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x90, 0x00 +}; + +const uint8_t kMaskBursty4_4[8] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00 +}; + +const uint8_t kMaskBursty5_1[2] = { + 0xf8, 0x00 +}; + +const uint8_t kMaskBursty5_2[4] = { + 0xd0, 0x00, + 0xa8, 0x00 +}; + +const uint8_t kMaskBursty5_3[6] = { + 0x70, 0x00, + 0x90, 0x00, + 0xc8, 0x00 +}; + +const uint8_t kMaskBursty5_4[8] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x88, 0x00 +}; + +const uint8_t kMaskBursty5_5[10] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00 +}; + +const uint8_t kMaskBursty6_1[2] = { + 0xfc, 0x00 +}; + +const uint8_t kMaskBursty6_2[4] = { + 0xa8, 0x00, + 0xd4, 0x00 +}; + +const uint8_t kMaskBursty6_3[6] = { + 0x94, 0x00, + 0xc8, 0x00, + 0x64, 0x00 +}; + +const uint8_t kMaskBursty6_4[8] = { + 0x60, 0x00, + 0x38, 0x00, + 0x88, 0x00, + 0xc4, 0x00 +}; + +const uint8_t kMaskBursty6_5[10] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x84, 0x00 +}; + +const uint8_t kMaskBursty6_6[12] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00 +}; + +const uint8_t kMaskBursty7_1[2] = { + 0xfe, 0x00 +}; + +const uint8_t kMaskBursty7_2[4] = { + 0xd4, 0x00, + 0xaa, 0x00 +}; + +const uint8_t kMaskBursty7_3[6] = { + 0xc8, 0x00, + 0x74, 0x00, + 0x92, 0x00 +}; + +const uint8_t kMaskBursty7_4[8] = { + 0x38, 0x00, + 0x8a, 0x00, + 0xc4, 0x00, + 0x62, 0x00 +}; + +const uint8_t kMaskBursty7_5[10] = { + 0x60, 0x00, + 0x30, 0x00, + 0x1c, 0x00, + 0x84, 0x00, + 0xc2, 0x00 +}; + +const uint8_t kMaskBursty7_6[12] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x82, 0x00 +}; + +const uint8_t kMaskBursty7_7[14] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00 +}; + +const uint8_t kMaskBursty8_1[2] = { + 0xff, 0x00 +}; + +const uint8_t kMaskBursty8_2[4] = { + 0xaa, 0x00, + 0xd5, 0x00 +}; + +const uint8_t kMaskBursty8_3[6] = { + 0x74, 0x00, + 0x92, 0x00, + 0xc9, 0x00 +}; + +const uint8_t kMaskBursty8_4[8] = { + 0x8a, 0x00, + 0xc5, 0x00, + 0x62, 0x00, + 0x31, 0x00 +}; + +const uint8_t kMaskBursty8_5[10] = { + 0x30, 0x00, + 0x1c, 0x00, + 0x85, 0x00, + 0xc2, 0x00, + 0x61, 0x00 +}; + +const uint8_t kMaskBursty8_6[12] = { + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0e, 0x00, + 0x82, 0x00, + 0xc1, 0x00 +}; + +const uint8_t kMaskBursty8_7[14] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x81, 0x00 +}; + +const uint8_t kMaskBursty8_8[16] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00 +}; + +const uint8_t kMaskBursty9_1[2] = { + 0xff, 0x80 +}; + +const uint8_t kMaskBursty9_2[4] = { + 0xd5, 0x00, + 0xaa, 0x80 +}; + +const uint8_t kMaskBursty9_3[6] = { + 0x92, 0x00, + 0xc9, 0x00, + 0x74, 0x80 +}; + +const uint8_t kMaskBursty9_4[8] = { + 0xc5, 0x00, + 0x62, 0x00, + 0x39, 0x00, + 0x8a, 0x80 +}; + +const uint8_t kMaskBursty9_5[10] = { + 0x1c, 0x00, + 0x85, 0x00, + 0xc2, 0x80, + 0x61, 0x00, + 0x30, 0x80 +}; + +const uint8_t kMaskBursty9_6[12] = { + 0x30, 0x00, + 0x18, 0x00, + 0x0e, 0x00, + 0x82, 0x80, + 0xc1, 0x00, + 0x60, 0x80 +}; + +const uint8_t kMaskBursty9_7[14] = { + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x07, 0x00, + 0x81, 0x00, + 0xc0, 0x80 +}; + +const uint8_t kMaskBursty9_8[16] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x80, 0x80 +}; + +const uint8_t kMaskBursty9_9[18] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80 +}; + +const uint8_t kMaskBursty10_1[2] = { + 0xff, 0xc0 +}; + +const uint8_t kMaskBursty10_2[4] = { + 0xaa, 0x80, + 0xd5, 0x40 +}; + +const uint8_t kMaskBursty10_3[6] = { + 0xc9, 0x00, + 0x74, 0x80, + 0x92, 0x40 +}; + +const uint8_t kMaskBursty10_4[8] = { + 0x62, 0x00, + 0x39, 0x00, + 0x8a, 0x80, + 0xc5, 0x40 +}; + +const uint8_t kMaskBursty10_5[10] = { + 0x85, 0x00, + 0xc2, 0x80, + 0x61, 0x40, + 0x30, 0x80, + 0x18, 0x40 +}; + +const uint8_t kMaskBursty10_6[12] = { + 0x18, 0x00, + 0x0e, 0x00, + 0x82, 0x80, + 0xc1, 0x40, + 0x60, 0x80, + 0x30, 0x40 +}; + +const uint8_t kMaskBursty10_7[14] = { + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x07, 0x00, + 0x81, 0x40, + 0xc0, 0x80, + 0x60, 0x40 +}; + +const uint8_t kMaskBursty10_8[16] = { + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x80, 0x80, + 0xc0, 0x40 +}; + +const uint8_t kMaskBursty10_9[18] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x80, 0x40 +}; + +const uint8_t kMaskBursty10_10[20] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x00, 0xc0 +}; + +const uint8_t kMaskBursty11_1[2] = { + 0xff, 0xe0 +}; + +const uint8_t kMaskBursty11_2[4] = { + 0xd5, 0x40, + 0xaa, 0xa0 +}; + +const uint8_t kMaskBursty11_3[6] = { + 0x74, 0x80, + 0x92, 0x40, + 0xc9, 0x20 +}; + +const uint8_t kMaskBursty11_4[8] = { + 0x39, 0x00, + 0x8a, 0x80, + 0xc5, 0x40, + 0x62, 0x20 +}; + +const uint8_t kMaskBursty11_5[10] = { + 0xc2, 0xc0, + 0x61, 0x00, + 0x30, 0xa0, + 0x1c, 0x40, + 0x85, 0x20 +}; + +const uint8_t kMaskBursty11_6[12] = { + 0x0e, 0x00, + 0x82, 0x80, + 0xc1, 0x40, + 0x60, 0xa0, + 0x30, 0x40, + 0x18, 0x20 +}; + +const uint8_t kMaskBursty11_7[14] = { + 0x18, 0x00, + 0x0c, 0x00, + 0x07, 0x00, + 0x81, 0x40, + 0xc0, 0xa0, + 0x60, 0x40, + 0x30, 0x20 +}; + +const uint8_t kMaskBursty11_8[16] = { + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x40, + 0x80, 0xa0, + 0xc0, 0x40, + 0x60, 0x20 +}; + +const uint8_t kMaskBursty11_9[18] = { + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x80, 0x40, + 0xc0, 0x20 +}; + +const uint8_t kMaskBursty11_10[20] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x00, 0xc0, + 0x80, 0x20 +}; + +const uint8_t kMaskBursty11_11[22] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x00, 0xc0, + 0x00, 0x60 +}; + +const uint8_t kMaskBursty12_1[2] = { + 0xff, 0xf0 +}; + +const uint8_t kMaskBursty12_2[4] = { + 0xaa, 0xa0, + 0xd5, 0x50 +}; + +const uint8_t kMaskBursty12_3[6] = { + 0x92, 0x40, + 0xc9, 0x20, + 0x74, 0x90 +}; + +const uint8_t kMaskBursty12_4[8] = { + 0x8a, 0x80, + 0xc5, 0x40, + 0x62, 0x20, + 0x39, 0x10 +}; + +const uint8_t kMaskBursty12_5[10] = { + 0x61, 0x00, + 0x30, 0xa0, + 0x1c, 0x50, + 0x85, 0x20, + 0xc2, 0x90 +}; + +const uint8_t kMaskBursty12_6[12] = { + 0x82, 0x90, + 0xc1, 0x40, + 0x60, 0xa0, + 0x30, 0x50, + 0x18, 0x20, + 0x0c, 0x10 +}; + +const uint8_t kMaskBursty12_7[14] = { + 0x0c, 0x00, + 0x07, 0x00, + 0x81, 0x40, + 0xc0, 0xa0, + 0x60, 0x50, + 0x30, 0x20, + 0x18, 0x10 +}; + +const uint8_t kMaskBursty12_8[16] = { + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x80, 0xa0, + 0xc0, 0x50, + 0x60, 0x20, + 0x30, 0x10 +}; + +const uint8_t kMaskBursty12_9[18] = { + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x80, 0x50, + 0xc0, 0x20, + 0x60, 0x10 +}; + +const uint8_t kMaskBursty12_10[20] = { + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x00, 0xc0, + 0x80, 0x20, + 0xc0, 0x10 +}; + +const uint8_t kMaskBursty12_11[22] = { + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x00, 0xc0, + 0x00, 0x60, + 0x80, 0x10 +}; + +const uint8_t kMaskBursty12_12[24] = { + 0x80, 0x00, + 0xc0, 0x00, + 0x60, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0x0c, 0x00, + 0x06, 0x00, + 0x03, 0x00, + 0x01, 0x80, + 0x00, 0xc0, + 0x00, 0x60, + 0x00, 0x30 +}; + +const uint8_t* const kPacketMaskBursty1[1] = { + kMaskBursty1_1 +}; + +const uint8_t* const kPacketMaskBursty2[2] = { + kMaskBursty2_1, + kMaskBursty2_2 +}; + +const uint8_t* const kPacketMaskBursty3[3] = { + kMaskBursty3_1, + kMaskBursty3_2, + kMaskBursty3_3 +}; + +const uint8_t* const kPacketMaskBursty4[4] = { + kMaskBursty4_1, + kMaskBursty4_2, + kMaskBursty4_3, + kMaskBursty4_4 +}; + +const uint8_t* const kPacketMaskBursty5[5] = { + kMaskBursty5_1, + kMaskBursty5_2, + kMaskBursty5_3, + kMaskBursty5_4, + kMaskBursty5_5 +}; + +const uint8_t* const kPacketMaskBursty6[6] = { + kMaskBursty6_1, + kMaskBursty6_2, + kMaskBursty6_3, + kMaskBursty6_4, + kMaskBursty6_5, + kMaskBursty6_6 +}; + +const uint8_t* const kPacketMaskBursty7[7] = { + kMaskBursty7_1, + kMaskBursty7_2, + kMaskBursty7_3, + kMaskBursty7_4, + kMaskBursty7_5, + kMaskBursty7_6, + kMaskBursty7_7 +}; + +const uint8_t* const kPacketMaskBursty8[8] = { + kMaskBursty8_1, + kMaskBursty8_2, + kMaskBursty8_3, + kMaskBursty8_4, + kMaskBursty8_5, + kMaskBursty8_6, + kMaskBursty8_7, + kMaskBursty8_8 +}; + +const uint8_t* const kPacketMaskBursty9[9] = { + kMaskBursty9_1, + kMaskBursty9_2, + kMaskBursty9_3, + kMaskBursty9_4, + kMaskBursty9_5, + kMaskBursty9_6, + kMaskBursty9_7, + kMaskBursty9_8, + kMaskBursty9_9 +}; + +const uint8_t* const kPacketMaskBursty10[10] = { + kMaskBursty10_1, + kMaskBursty10_2, + kMaskBursty10_3, + kMaskBursty10_4, + kMaskBursty10_5, + kMaskBursty10_6, + kMaskBursty10_7, + kMaskBursty10_8, + kMaskBursty10_9, + kMaskBursty10_10 +}; + +const uint8_t* const kPacketMaskBursty11[11] = { + kMaskBursty11_1, + kMaskBursty11_2, + kMaskBursty11_3, + kMaskBursty11_4, + kMaskBursty11_5, + kMaskBursty11_6, + kMaskBursty11_7, + kMaskBursty11_8, + kMaskBursty11_9, + kMaskBursty11_10, + kMaskBursty11_11 +}; + +const uint8_t* const kPacketMaskBursty12[12] = { + kMaskBursty12_1, + kMaskBursty12_2, + kMaskBursty12_3, + kMaskBursty12_4, + kMaskBursty12_5, + kMaskBursty12_6, + kMaskBursty12_7, + kMaskBursty12_8, + kMaskBursty12_9, + kMaskBursty12_10, + kMaskBursty12_11, + kMaskBursty12_12 +}; + +const uint8_t* const* const kPacketMaskBurstyTbl[12] = { + kPacketMaskBursty1, + kPacketMaskBursty2, + kPacketMaskBursty3, + kPacketMaskBursty4, + kPacketMaskBursty5, + kPacketMaskBursty6, + kPacketMaskBursty7, + kPacketMaskBursty8, + kPacketMaskBursty9, + kPacketMaskBursty10, + kPacketMaskBursty11, + kPacketMaskBursty12 +}; + +} // namespace fec_private_tables +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_random.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_random.h new file mode 100644 index 0000000000..4d490a182a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_random.h @@ -0,0 +1,24524 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_RANDOM_H_ +#define MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_RANDOM_H_ + +// This file contains a set of packets masks for the FEC code. The masks in +// this table are specifically designed to favor recovery to random loss. +// These packet masks are defined to protect up to maximum of 48 media packets. + +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace fec_private_tables { + +const uint8_t kMaskRandom10_1[2] = { + 0xff, 0xc0 +}; + +const uint8_t kMaskRandom10_10[20] = { + 0x4c, 0x00, + 0x51, 0x00, + 0xa0, 0x40, + 0x04, 0xc0, + 0x03, 0x80, + 0x86, 0x00, + 0x29, 0x00, + 0x42, 0x40, + 0x98, 0x00, + 0x30, 0x80 +}; + +const uint8_t kMaskRandom10_2[4] = { + 0xaa, 0x80, + 0xd5, 0x40 +}; + +const uint8_t kMaskRandom10_3[6] = { + 0xa4, 0x40, + 0xc9, 0x00, + 0x52, 0x80 +}; + +const uint8_t kMaskRandom10_4[8] = { + 0xca, 0x00, + 0x32, 0x80, + 0xa1, 0x40, + 0x55, 0x00 +}; + +const uint8_t kMaskRandom10_5[10] = { + 0xca, 0x00, + 0x32, 0x80, + 0xa1, 0x40, + 0x55, 0x00, + 0x08, 0xc0 +}; + +const uint8_t kMaskRandom10_6[12] = { + 0x0e, 0x00, + 0x33, 0x00, + 0x10, 0xc0, + 0x45, 0x40, + 0x88, 0x80, + 0xe0, 0x00 +}; + +const uint8_t kMaskRandom10_7[14] = { + 0x46, 0x00, + 0x33, 0x00, + 0x80, 0xc0, + 0x0c, 0x40, + 0x28, 0x80, + 0x94, 0x00, + 0xc1, 0x00 +}; + +const uint8_t kMaskRandom10_8[16] = { + 0x2c, 0x00, + 0x81, 0x80, + 0xa0, 0x40, + 0x05, 0x40, + 0x18, 0x80, + 0xc2, 0x00, + 0x22, 0x80, + 0x50, 0x40 +}; + +const uint8_t kMaskRandom10_9[18] = { + 0x4c, 0x00, + 0x23, 0x00, + 0x88, 0xc0, + 0x21, 0x40, + 0x52, 0x80, + 0x94, 0x00, + 0x26, 0x00, + 0x48, 0x40, + 0x91, 0x80 +}; + +const uint8_t kMaskRandom11_1[2] = { + 0xff, 0xe0 +}; + +const uint8_t kMaskRandom11_10[20] = { + 0x64, 0x40, + 0x51, 0x40, + 0xa9, 0x00, + 0x04, 0xc0, + 0xd0, 0x00, + 0x82, 0x40, + 0x21, 0x20, + 0x0c, 0x20, + 0x4a, 0x00, + 0x12, 0xa0 +}; + +const uint8_t kMaskRandom11_11[22] = { + 0x46, 0x40, + 0x33, 0x20, + 0x99, 0x00, + 0x05, 0x80, + 0x80, 0xa0, + 0x84, 0x40, + 0x40, 0x60, + 0x0a, 0x80, + 0x68, 0x00, + 0x10, 0x20, + 0x30, 0x40 +}; + +const uint8_t kMaskRandom11_2[4] = { + 0xec, 0xc0, + 0x9b, 0xa0 +}; + +const uint8_t kMaskRandom11_3[6] = { + 0xca, 0xc0, + 0xf1, 0x40, + 0xb6, 0x20 +}; + +const uint8_t kMaskRandom11_4[8] = { + 0xc4, 0xc0, + 0x31, 0x60, + 0x4b, 0x20, + 0x2c, 0xa0 +}; + +const uint8_t kMaskRandom11_5[10] = { + 0x86, 0x80, + 0x23, 0x20, + 0x16, 0x20, + 0x4c, 0x20, + 0x41, 0xc0 +}; + +const uint8_t kMaskRandom11_6[12] = { + 0x64, 0x40, + 0x51, 0x40, + 0x0c, 0xa0, + 0xa1, 0x20, + 0x12, 0xa0, + 0x8a, 0x40 +}; + +const uint8_t kMaskRandom11_7[14] = { + 0x46, 0x40, + 0x33, 0x20, + 0x91, 0x80, + 0xa4, 0x20, + 0x50, 0xa0, + 0x84, 0xc0, + 0x09, 0x60 +}; + +const uint8_t kMaskRandom11_8[16] = { + 0x0c, 0x80, + 0x80, 0x60, + 0xa0, 0x80, + 0x05, 0x40, + 0x43, 0x00, + 0x1a, 0x00, + 0x60, 0x20, + 0x14, 0x20 +}; + +const uint8_t kMaskRandom11_9[18] = { + 0x46, 0x40, + 0x62, 0x60, + 0x8c, 0x00, + 0x01, 0x60, + 0x07, 0x80, + 0xa0, 0x80, + 0x18, 0xa0, + 0x91, 0x00, + 0x78, 0x00 +}; + +const uint8_t kMaskRandom12_1[2] = { + 0xff, 0xf0 +}; + +const uint8_t kMaskRandom12_10[20] = { + 0x51, 0x40, + 0x45, 0x10, + 0x80, 0xd0, + 0x24, 0x20, + 0x0a, 0x20, + 0x00, 0xe0, + 0xb8, 0x00, + 0x09, 0x10, + 0x56, 0x00, + 0xa2, 0x80 +}; + +const uint8_t kMaskRandom12_11[22] = { + 0x53, 0x60, + 0x21, 0x30, + 0x10, 0x90, + 0x00, 0x70, + 0x0c, 0x10, + 0x40, 0xc0, + 0x6a, 0x00, + 0x86, 0x00, + 0x24, 0x80, + 0x89, 0x00, + 0xc0, 0x20 +}; + +const uint8_t kMaskRandom12_12[24] = { + 0x10, 0x60, + 0x02, 0x30, + 0x40, 0x50, + 0x21, 0x80, + 0x81, 0x10, + 0x14, 0x80, + 0x98, 0x00, + 0x08, 0x90, + 0x62, 0x00, + 0x24, 0x20, + 0x8a, 0x00, + 0x84, 0x40 +}; + +const uint8_t kMaskRandom12_2[4] = { + 0xec, 0xc0, + 0x93, 0xb0 +}; + +const uint8_t kMaskRandom12_3[6] = { + 0x9b, 0x80, + 0x4f, 0x10, + 0x3c, 0x60 +}; + +const uint8_t kMaskRandom12_4[8] = { + 0x8b, 0x20, + 0x14, 0xb0, + 0x22, 0xd0, + 0x45, 0x50 +}; + +const uint8_t kMaskRandom12_5[10] = { + 0x53, 0x60, + 0x64, 0x20, + 0x0c, 0xc0, + 0x82, 0xa0, + 0x09, 0x30 +}; + +const uint8_t kMaskRandom12_6[12] = { + 0x51, 0x40, + 0xc5, 0x10, + 0x21, 0x80, + 0x12, 0x30, + 0x08, 0xe0, + 0x2e, 0x00 +}; + +const uint8_t kMaskRandom12_7[14] = { + 0x53, 0x60, + 0x21, 0x30, + 0x90, 0x90, + 0x02, 0x50, + 0x06, 0xa0, + 0x2c, 0x00, + 0x88, 0x60 +}; + +const uint8_t kMaskRandom12_8[16] = { + 0x20, 0x60, + 0x80, 0x30, + 0x42, 0x40, + 0x01, 0x90, + 0x14, 0x10, + 0x0a, 0x80, + 0x38, 0x00, + 0xc5, 0x00 +}; + +const uint8_t kMaskRandom12_9[18] = { + 0x53, 0x60, + 0xe4, 0x20, + 0x24, 0x40, + 0xa1, 0x10, + 0x18, 0x30, + 0x03, 0x90, + 0x8a, 0x10, + 0x04, 0x90, + 0x00, 0xe0 +}; + +const uint8_t kMaskRandom13_1[2] = { + 0xff, 0xf8 +}; + +const uint8_t kMaskRandom13_10[20] = { + 0xd1, 0x00, + 0x44, 0x50, + 0x10, 0x98, + 0xa0, 0x50, + 0x4a, 0x08, + 0x40, 0x30, + 0x80, 0x28, + 0x0c, 0x90, + 0x05, 0x88, + 0x62, 0x20 +}; + +const uint8_t kMaskRandom13_11[22] = { + 0x51, 0x20, + 0x22, 0x10, + 0x13, 0x40, + 0x25, 0x00, + 0x18, 0x18, + 0x0a, 0x20, + 0x88, 0x88, + 0x06, 0x80, + 0xe0, 0x20, + 0x84, 0x40, + 0x44, 0x18 +}; + +const uint8_t kMaskRandom13_12[24] = { + 0x28, 0x28, + 0x84, 0x50, + 0x60, 0x40, + 0x05, 0x48, + 0x02, 0x98, + 0x01, 0x30, + 0x48, 0x10, + 0x24, 0x80, + 0x94, 0x00, + 0x8a, 0x00, + 0x11, 0x80, + 0x52, 0x20 +}; + +const uint8_t kMaskRandom13_13[26] = { + 0x51, 0x20, + 0x66, 0x40, + 0x05, 0x48, + 0x81, 0x20, + 0x94, 0x00, + 0x30, 0x80, + 0x21, 0x10, + 0x03, 0xc0, + 0xe8, 0x00, + 0x0a, 0x10, + 0x80, 0x18, + 0x04, 0x90, + 0x08, 0xa8 +}; + +const uint8_t kMaskRandom13_2[4] = { + 0xec, 0xc0, + 0x1b, 0x38 +}; + +const uint8_t kMaskRandom13_3[6] = { + 0x99, 0xb0, + 0x46, 0xd8, + 0x37, 0x28 +}; + +const uint8_t kMaskRandom13_4[8] = { + 0x49, 0xb0, + 0x26, 0xd0, + 0x85, 0x68, + 0x52, 0x58 +}; + +const uint8_t kMaskRandom13_5[10] = { + 0x51, 0x30, + 0x66, 0x40, + 0x0c, 0x68, + 0xa1, 0xc0, + 0x22, 0x98 +}; + +const uint8_t kMaskRandom13_6[12] = { + 0xd1, 0x20, + 0x46, 0xd0, + 0x15, 0x48, + 0x21, 0x70, + 0x28, 0xc8, + 0xaa, 0x20 +}; + +const uint8_t kMaskRandom13_7[14] = { + 0x59, 0x20, + 0x26, 0x50, + 0xb1, 0x40, + 0x2b, 0x08, + 0x14, 0xc8, + 0xc8, 0x88, + 0x84, 0xb0 +}; + +const uint8_t kMaskRandom13_8[16] = { + 0x80, 0xa8, + 0x30, 0x90, + 0x16, 0x08, + 0x03, 0x30, + 0x44, 0x60, + 0x08, 0x18, + 0xd8, 0x00, + 0xa1, 0x40 +}; + +const uint8_t kMaskRandom13_9[18] = { + 0x59, 0x20, + 0x66, 0x40, + 0x14, 0x40, + 0x21, 0x48, + 0x02, 0xc8, + 0x94, 0x10, + 0x80, 0xa8, + 0x0a, 0x90, + 0x40, 0x18 +}; + +const uint8_t kMaskRandom14_1[2] = { + 0xff, 0xfc +}; + +const uint8_t kMaskRandom14_10[20] = { + 0xc0, 0xd4, + 0x1d, 0x40, + 0xd4, 0x08, + 0x02, 0x60, + 0x04, 0x28, + 0x20, 0x98, + 0x40, 0x44, + 0x08, 0x84, + 0x68, 0x00, + 0x23, 0x10 +}; + +const uint8_t kMaskRandom14_11[22] = { + 0x62, 0xd0, + 0x35, 0x20, + 0x14, 0x14, + 0xc5, 0x08, + 0x22, 0x0c, + 0x88, 0xb8, + 0x42, 0x54, + 0x28, 0xa4, + 0x94, 0x20, + 0x1b, 0x04, + 0x22, 0xc0 +}; + +const uint8_t kMaskRandom14_12[24] = { + 0x81, 0x04, + 0x40, 0x68, + 0x90, 0x24, + 0x28, 0x28, + 0x52, 0x10, + 0x41, 0x88, + 0x09, 0x30, + 0x48, 0x44, + 0x04, 0x44, + 0x0e, 0x80, + 0xa5, 0x90, + 0x12, 0x0c +}; + +const uint8_t kMaskRandom14_13[26] = { + 0x62, 0x54, + 0x34, 0x60, + 0x48, 0x04, + 0x00, 0xac, + 0x28, 0x08, + 0x81, 0x08, + 0x23, 0x04, + 0x06, 0x80, + 0x80, 0x14, + 0x30, 0x10, + 0x8c, 0x20, + 0x54, 0x00, + 0x80, 0xc0 +}; + +const uint8_t kMaskRandom14_14[28] = { + 0x40, 0x54, + 0x15, 0x40, + 0xc0, 0x04, + 0x28, 0x10, + 0x05, 0x0c, + 0x64, 0x80, + 0x81, 0x80, + 0x10, 0x98, + 0x84, 0x20, + 0x12, 0x30, + 0x62, 0x00, + 0x28, 0x60, + 0x0e, 0x08, + 0x10, 0x84 +}; + +const uint8_t kMaskRandom14_2[4] = { + 0xec, 0xe8, + 0x3b, 0x9c +}; + +const uint8_t kMaskRandom14_3[6] = { + 0xac, 0xd8, + 0x55, 0x6c, + 0x27, 0xb4 +}; + +const uint8_t kMaskRandom14_4[8] = { + 0x2c, 0xd8, + 0x93, 0x68, + 0x1a, 0xb4, + 0x47, 0x2c +}; + +const uint8_t kMaskRandom14_5[10] = { + 0x64, 0xd8, + 0xa5, 0x68, + 0x52, 0xb4, + 0x1d, 0xa8, + 0x9c, 0x54 +}; + +const uint8_t kMaskRandom14_6[12] = { + 0x4a, 0x54, + 0x95, 0x48, + 0x14, 0xb4, + 0x51, 0xa8, + 0x22, 0x6c, + 0x88, 0x8c +}; + +const uint8_t kMaskRandom14_7[14] = { + 0x62, 0x54, + 0xb9, 0x20, + 0x18, 0xb4, + 0x54, 0x98, + 0x06, 0x6c, + 0x85, 0x54, + 0xaa, 0x88 +}; + +const uint8_t kMaskRandom14_8[16] = { + 0xc0, 0x14, + 0x41, 0x60, + 0x88, 0x30, + 0x20, 0xa4, + 0x0a, 0x48, + 0x04, 0x98, + 0x94, 0x40, + 0x72, 0x00 +}; + +const uint8_t kMaskRandom14_9[18] = { + 0xa2, 0x54, + 0x34, 0x60, + 0x4a, 0x24, + 0x20, 0xa8, + 0x11, 0x84, + 0x49, 0x08, + 0x86, 0x0c, + 0x20, 0xd4, + 0x88, 0x48 +}; + +const uint8_t kMaskRandom15_1[2] = { + 0xff, 0xfe +}; + +const uint8_t kMaskRandom15_10[20] = { + 0xc0, 0xa0, + 0x15, 0x56, + 0x74, 0x40, + 0x00, 0x9c, + 0x01, 0x2c, + 0x44, 0x92, + 0x88, 0x50, + 0x20, 0xa4, + 0xaa, 0x04, + 0x02, 0x62 +}; + +const uint8_t kMaskRandom15_11[22] = { + 0x62, 0x22, + 0xf1, 0x10, + 0x10, 0x0e, + 0x10, 0xb0, + 0x24, 0x24, + 0x01, 0x12, + 0x00, 0xc4, + 0x04, 0xa2, + 0x02, 0x58, + 0x2b, 0x00, + 0x98, 0x40 +}; + +const uint8_t kMaskRandom15_12[24] = { + 0x88, 0x90, + 0x40, 0x54, + 0x82, 0x62, + 0x21, 0xa4, + 0x10, 0x64, + 0x44, 0x0a, + 0x10, 0xc8, + 0x4d, 0x2a, + 0x38, 0x02, + 0x17, 0x48, + 0x90, 0x84, + 0x72, 0x14 +}; + +const uint8_t kMaskRandom15_13[26] = { + 0x62, 0xa2, + 0x34, 0x44, + 0x40, 0x4a, + 0xc4, 0x04, + 0x08, 0x60, + 0x94, 0x12, + 0x88, 0xc0, + 0x21, 0x32, + 0xc1, 0x40, + 0x10, 0x68, + 0x06, 0x90, + 0x59, 0x00, + 0x0a, 0x0c +}; + +const uint8_t kMaskRandom15_14[28] = { + 0x40, 0x82, + 0x15, 0x54, + 0x88, 0x12, + 0xc0, 0x10, + 0x80, 0xa0, + 0x01, 0x22, + 0x40, 0x2c, + 0x22, 0x02, + 0x90, 0x04, + 0x12, 0x40, + 0x5d, 0x00, + 0x20, 0x54, + 0x86, 0x08, + 0x28, 0x88 +}; + +const uint8_t kMaskRandom15_15[30] = { + 0x62, 0x22, + 0x31, 0x10, + 0x58, 0x00, + 0x01, 0x12, + 0x88, 0x20, + 0x44, 0x02, + 0x29, 0x04, + 0x82, 0xa0, + 0x0a, 0x1a, + 0x11, 0xe0, + 0x84, 0x04, + 0x86, 0x40, + 0x00, 0x86, + 0x44, 0x48, + 0x10, 0x98 +}; + +const uint8_t kMaskRandom15_2[4] = { + 0xec, 0xea, + 0xbb, 0x9c +}; + +const uint8_t kMaskRandom15_3[6] = { + 0xac, 0x92, + 0x55, 0x4a, + 0x43, 0x36 +}; + +const uint8_t kMaskRandom15_4[8] = { + 0x25, 0xaa, + 0x95, 0x54, + 0x1a, 0x6a, + 0x43, 0xd4 +}; + +const uint8_t kMaskRandom15_5[10] = { + 0x64, 0xa2, + 0x25, 0x54, + 0x49, 0x68, + 0x53, 0x90, + 0x8e, 0x30 +}; + +const uint8_t kMaskRandom15_6[12] = { + 0x62, 0x8a, + 0x15, 0x54, + 0x4c, 0x46, + 0x52, 0x94, + 0x23, 0x64, + 0x8a, 0x58 +}; + +const uint8_t kMaskRandom15_7[14] = { + 0x62, 0xa2, + 0xb1, 0x14, + 0x18, 0x6a, + 0x44, 0xd4, + 0x13, 0x64, + 0x49, 0x1a, + 0x86, 0x8c +}; + +const uint8_t kMaskRandom15_8[16] = { + 0x90, 0x22, + 0x09, 0x50, + 0x00, 0x6a, + 0x20, 0x34, + 0x14, 0x44, + 0xc2, 0x10, + 0x00, 0xc6, + 0x65, 0x80 +}; + +const uint8_t kMaskRandom15_9[18] = { + 0x62, 0x22, + 0x24, 0x44, + 0xc0, 0x50, + 0x03, 0x0c, + 0x16, 0x28, + 0x89, 0x00, + 0x82, 0x90, + 0x08, 0xa4, + 0x90, 0x48 +}; + +const uint8_t kMaskRandom16_1[2] = { + 0xff, 0xff +}; + +const uint8_t kMaskRandom16_10[20] = { + 0x45, 0x51, + 0x10, 0xa2, + 0x01, 0x25, + 0x0b, 0x42, + 0xd8, 0x20, + 0x82, 0x8c, + 0x24, 0x4a, + 0x38, 0x18, + 0x2a, 0x25, + 0x84, 0x92 +}; + +const uint8_t kMaskRandom16_11[22] = { + 0x55, 0x55, + 0x2a, 0x22, + 0x31, 0x11, + 0x83, 0x42, + 0x06, 0x98, + 0x40, 0xe1, + 0x2c, 0x44, + 0xd8, 0x28, + 0x92, 0x81, + 0x84, 0x32, + 0x68, 0x0c +}; + +const uint8_t kMaskRandom16_12[24] = { + 0x84, 0x31, + 0x18, 0xa2, + 0x4e, 0x01, + 0x44, 0xc8, + 0x0e, 0x90, + 0x20, 0xcc, + 0x93, 0x40, + 0x2d, 0x10, + 0x31, 0x44, + 0xc0, 0x23, + 0x11, 0x25, + 0xe8, 0x80 +}; + +const uint8_t kMaskRandom16_13[26] = { + 0x45, 0x15, + 0x22, 0x22, + 0x96, 0x0c, + 0x0c, 0x50, + 0x62, 0x04, + 0x49, 0x06, + 0x11, 0x82, + 0x12, 0x38, + 0x40, 0x71, + 0xa8, 0x8a, + 0x08, 0xa1, + 0xa0, 0xc0, + 0xc5, 0x10 +}; + +const uint8_t kMaskRandom16_14[28] = { + 0x45, 0x51, + 0x22, 0x0a, + 0x84, 0xd0, + 0x0c, 0x8a, + 0x18, 0x06, + 0x30, 0x03, + 0x61, 0x08, + 0x40, 0x11, + 0x10, 0x2c, + 0x09, 0x60, + 0x00, 0x94, + 0x52, 0x40, + 0xa4, 0x24, + 0x82, 0x88 +}; + +const uint8_t kMaskRandom16_15[30] = { + 0x55, 0x11, + 0x22, 0x22, + 0x11, 0x11, + 0x80, 0x45, + 0x20, 0x1a, + 0x08, 0x68, + 0x22, 0x84, + 0x48, 0x09, + 0x07, 0x01, + 0x94, 0x20, + 0x82, 0x06, + 0x60, 0x48, + 0x89, 0x80, + 0x00, 0x8e, + 0x18, 0x22 +}; + +const uint8_t kMaskRandom16_16[32] = { + 0xa4, 0x10, + 0x01, 0x2a, + 0x06, 0x42, + 0x08, 0x68, + 0x81, 0x90, + 0x00, 0xf0, + 0x50, 0x05, + 0x20, 0x51, + 0x43, 0x08, + 0x68, 0x80, + 0x80, 0x0b, + 0x10, 0x4c, + 0x12, 0x30, + 0x40, 0x85, + 0x0e, 0x04, + 0x18, 0x12 +}; + +const uint8_t kMaskRandom16_2[4] = { + 0xae, 0xae, + 0x79, 0x79 +}; + +const uint8_t kMaskRandom16_3[6] = { + 0xad, 0x2d, + 0x76, 0x36, + 0x26, 0xdb +}; + +const uint8_t kMaskRandom16_4[8] = { + 0x55, 0x55, + 0xaa, 0xaa, + 0x35, 0x35, + 0xca, 0xca +}; + +const uint8_t kMaskRandom16_5[10] = { + 0x55, 0x55, + 0x2a, 0x2a, + 0x24, 0x25, + 0x84, 0xc8, + 0x10, 0xb6 +}; + +const uint8_t kMaskRandom16_6[12] = { + 0x51, 0x51, + 0x0a, 0x2a, + 0xa2, 0x15, + 0x84, 0x4a, + 0x30, 0x92, + 0x04, 0xac +}; + +const uint8_t kMaskRandom16_7[14] = { + 0x45, 0x51, + 0x22, 0x2a, + 0x91, 0x11, + 0x2e, 0x08, + 0x48, 0x34, + 0x90, 0x29, + 0x09, 0x86 +}; + +const uint8_t kMaskRandom16_8[16] = { + 0x20, 0x54, + 0x18, 0x88, + 0x84, 0x07, + 0x60, 0x48, + 0x12, 0x82, + 0x81, 0x41, + 0x40, 0x62, + 0x16, 0x30 +}; + +const uint8_t kMaskRandom16_9[18] = { + 0x55, 0x51, + 0x22, 0x2a, + 0x05, 0x85, + 0x09, 0x4a, + 0x84, 0x32, + 0xc0, 0x0d, + 0x20, 0xa6, + 0x1a, 0x09, + 0x44, 0x64 +}; + +const uint8_t kMaskRandom17_1[6] = { + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_10[60] = { + 0x55, 0x8c, 0x80, 0x00, 0x00, 0x00, + 0xaa, 0x27, 0x00, 0x00, 0x00, 0x00, + 0xa5, 0x32, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x61, 0x80, 0x00, 0x00, 0x00, + 0x3c, 0x5c, 0x00, 0x00, 0x00, 0x00, + 0x8e, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x6a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x32, 0x80, 0x00, 0x00, 0x00, + 0xd1, 0x25, 0x80, 0x00, 0x00, 0x00, + 0xc8, 0x02, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_11[66] = { + 0x55, 0x8c, 0x80, 0x00, 0x00, 0x00, + 0xaa, 0x27, 0x00, 0x00, 0x00, 0x00, + 0xa5, 0x32, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x61, 0x80, 0x00, 0x00, 0x00, + 0x3c, 0x5c, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x84, 0x80, 0x00, 0x00, 0x00, + 0xa2, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x95, 0x51, 0x80, 0x00, 0x00, 0x00, + 0x4a, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x89, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_12[72] = { + 0x51, 0x84, 0x80, 0x00, 0x00, 0x00, + 0xa2, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x95, 0x51, 0x80, 0x00, 0x00, 0x00, + 0x4a, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x89, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x8c, 0x80, 0x00, 0x00, 0x00, + 0xaa, 0x27, 0x00, 0x00, 0x00, 0x00, + 0xa5, 0x32, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x61, 0x80, 0x00, 0x00, 0x00, + 0x3c, 0x5c, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x35, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_13[78] = { + 0x51, 0x84, 0x80, 0x00, 0x00, 0x00, + 0xa2, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x95, 0x51, 0x80, 0x00, 0x00, 0x00, + 0x4a, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x89, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x8c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x81, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x28, 0x80, 0x00, 0x00, 0x00, + 0x83, 0x34, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_14[84] = { + 0x15, 0x8c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x81, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x28, 0x80, 0x00, 0x00, 0x00, + 0x83, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x84, 0x80, 0x00, 0x00, 0x00, + 0xa2, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x95, 0x51, 0x80, 0x00, 0x00, 0x00, + 0x4a, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x89, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0xde, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_15[90] = { + 0x15, 0x8c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x81, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x28, 0x80, 0x00, 0x00, 0x00, + 0x83, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x91, 0x00, 0x00, 0x00, 0x00, + 0x91, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x68, 0x06, 0x80, 0x00, 0x00, 0x00, + 0x32, 0xc8, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x45, 0x00, 0x00, 0x00, 0x00, + 0xc4, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x1c, 0xa2, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_16[96] = { + 0x25, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x91, 0x00, 0x00, 0x00, 0x00, + 0x91, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x68, 0x06, 0x80, 0x00, 0x00, 0x00, + 0x32, 0xc8, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x45, 0x00, 0x00, 0x00, 0x00, + 0xc4, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x1c, 0xa2, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x8c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x81, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x28, 0x80, 0x00, 0x00, 0x00, + 0x83, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x1c, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_17[102] = { + 0x25, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x91, 0x00, 0x00, 0x00, 0x00, + 0x91, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x68, 0x06, 0x80, 0x00, 0x00, 0x00, + 0x32, 0xc8, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x45, 0x00, 0x00, 0x00, 0x00, + 0xc4, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x1c, 0xa2, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x4c, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x91, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x42, 0x80, 0x00, 0x00, 0x00, + 0x32, 0xa4, 0x00, 0x00, 0x00, 0x00, + 0x43, 0x13, 0x00, 0x00, 0x00, 0x00, + 0xc4, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x1c, 0x88, 0x80, 0x00, 0x00, 0x00, + 0x3c, 0x09, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_2[12] = { + 0xce, 0xce, 0x00, 0x00, 0x00, 0x00, + 0xb9, 0x39, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_3[18] = { + 0xcd, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x97, 0x27, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0xd1, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_4[24] = { + 0xca, 0xec, 0x00, 0x00, 0x00, 0x00, + 0xa9, 0x67, 0x00, 0x00, 0x00, 0x00, + 0x3a, 0xb1, 0x80, 0x00, 0x00, 0x00, + 0x55, 0x5a, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_5[30] = { + 0x55, 0x44, 0x80, 0x00, 0x00, 0x00, + 0x2a, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x25, 0xa1, 0x80, 0x00, 0x00, 0x00, + 0xe2, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x99, 0x98, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_6[36] = { + 0xd1, 0x4c, 0x00, 0x00, 0x00, 0x00, + 0xa2, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x95, 0x30, 0x80, 0x00, 0x00, 0x00, + 0xca, 0x0a, 0x80, 0x00, 0x00, 0x00, + 0xa4, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_7[42] = { + 0x15, 0x44, 0x80, 0x00, 0x00, 0x00, + 0x8a, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x85, 0x91, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x0a, 0x80, 0x00, 0x00, 0x00, + 0x58, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x43, 0xc8, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_8[48] = { + 0x64, 0x16, 0x00, 0x00, 0x00, 0x00, + 0xa2, 0xc2, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x60, 0x80, 0x00, 0x00, 0x00, + 0x4a, 0x85, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x4c, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x29, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x94, 0xb0, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom17_9[54] = { + 0x8e, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x6a, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x32, 0x80, 0x00, 0x00, 0x00, + 0xd1, 0x25, 0x80, 0x00, 0x00, 0x00, + 0x55, 0x8c, 0x80, 0x00, 0x00, 0x00, + 0xaa, 0x27, 0x00, 0x00, 0x00, 0x00, + 0xa5, 0x32, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x61, 0x80, 0x00, 0x00, 0x00, + 0x3c, 0x5c, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_1[6] = { + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_10[60] = { + 0x8c, 0xc6, 0x40, 0x00, 0x00, 0x00, + 0x27, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x32, 0x99, 0x40, 0x00, 0x00, 0x00, + 0x61, 0xb0, 0xc0, 0x00, 0x00, 0x00, + 0x5c, 0x2e, 0x00, 0x00, 0x00, 0x00, + 0xcc, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x15, 0x80, 0x00, 0x00, 0x00, + 0x32, 0x99, 0x40, 0x00, 0x00, 0x00, + 0x25, 0x92, 0xc0, 0x00, 0x00, 0x00, + 0xfd, 0x9d, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_11[66] = { + 0x8c, 0xc6, 0x40, 0x00, 0x00, 0x00, + 0x27, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x32, 0x99, 0x40, 0x00, 0x00, 0x00, + 0x61, 0xb0, 0xc0, 0x00, 0x00, 0x00, + 0x5c, 0x2e, 0x00, 0x00, 0x00, 0x00, + 0x84, 0xc2, 0x40, 0x00, 0x00, 0x00, + 0x27, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x51, 0xa8, 0xc0, 0x00, 0x00, 0x00, + 0x1a, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x44, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_12[72] = { + 0x84, 0xc2, 0x40, 0x00, 0x00, 0x00, + 0x27, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x51, 0xa8, 0xc0, 0x00, 0x00, 0x00, + 0x1a, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x44, 0x80, 0x00, 0x00, 0x00, + 0x8c, 0xc6, 0x40, 0x00, 0x00, 0x00, + 0x27, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x32, 0x99, 0x40, 0x00, 0x00, 0x00, + 0x61, 0xb0, 0xc0, 0x00, 0x00, 0x00, + 0x5c, 0x2e, 0x00, 0x00, 0x00, 0x00, + 0x5b, 0x0c, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_13[78] = { + 0x84, 0xc2, 0x40, 0x00, 0x00, 0x00, + 0x27, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x51, 0xa8, 0xc0, 0x00, 0x00, 0x00, + 0x1a, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x44, 0x80, 0x00, 0x00, 0x00, + 0x8c, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x23, 0x80, 0x00, 0x00, 0x00, + 0x81, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0x89, 0x40, 0x00, 0x00, 0x00, + 0x58, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x40, 0x00, 0x00, 0x00, + 0x34, 0x1a, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_14[84] = { + 0x8c, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x23, 0x80, 0x00, 0x00, 0x00, + 0x81, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0x89, 0x40, 0x00, 0x00, 0x00, + 0x58, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x40, 0x00, 0x00, 0x00, + 0x34, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x84, 0xc2, 0x40, 0x00, 0x00, 0x00, + 0x27, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x51, 0xa8, 0xc0, 0x00, 0x00, 0x00, + 0x1a, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x44, 0x80, 0x00, 0x00, 0x00, + 0x7f, 0x4f, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_15[90] = { + 0x8c, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x23, 0x80, 0x00, 0x00, 0x00, + 0x81, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0x89, 0x40, 0x00, 0x00, 0x00, + 0x58, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x40, 0x00, 0x00, 0x00, + 0x34, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x48, 0x80, 0x00, 0x00, 0x00, + 0xc0, 0xe0, 0x40, 0x00, 0x00, 0x00, + 0x06, 0x83, 0x40, 0x00, 0x00, 0x00, + 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x98, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x51, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_16[96] = { + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x48, 0x80, 0x00, 0x00, 0x00, + 0xc0, 0xe0, 0x40, 0x00, 0x00, 0x00, + 0x06, 0x83, 0x40, 0x00, 0x00, 0x00, + 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x98, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x8c, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x23, 0x80, 0x00, 0x00, 0x00, + 0x81, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0x89, 0x40, 0x00, 0x00, 0x00, + 0x58, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x40, 0x00, 0x00, 0x00, + 0x34, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0xef, 0xf2, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_17[102] = { + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x48, 0x80, 0x00, 0x00, 0x00, + 0xc0, 0xe0, 0x40, 0x00, 0x00, 0x00, + 0x06, 0x83, 0x40, 0x00, 0x00, 0x00, + 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x98, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x48, 0x80, 0x00, 0x00, 0x00, + 0x42, 0xa1, 0x40, 0x00, 0x00, 0x00, + 0xa4, 0x52, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x09, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x98, 0x40, 0x00, 0x00, 0x00, + 0x88, 0xc4, 0x40, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_18[108] = { + 0x4c, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x48, 0x80, 0x00, 0x00, 0x00, + 0x42, 0xa1, 0x40, 0x00, 0x00, 0x00, + 0xa4, 0x52, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x09, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x98, 0x40, 0x00, 0x00, 0x00, + 0x88, 0xc4, 0x40, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x80, 0x00, 0x00, 0x00, + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x48, 0x80, 0x00, 0x00, 0x00, + 0xc0, 0xe0, 0x40, 0x00, 0x00, 0x00, + 0x06, 0x83, 0x40, 0x00, 0x00, 0x00, + 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x22, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x98, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x51, 0x00, 0x00, 0x00, 0x00, + 0xd0, 0x03, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_2[12] = { + 0xce, 0x67, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x9c, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_3[18] = { + 0xcc, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x15, 0x80, 0x00, 0x00, 0x00, + 0x92, 0xc9, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_4[24] = { + 0xec, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x67, 0x33, 0x80, 0x00, 0x00, 0x00, + 0xb1, 0xd8, 0xc0, 0x00, 0x00, 0x00, + 0x5a, 0xad, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_5[30] = { + 0x4c, 0xa6, 0x40, 0x00, 0x00, 0x00, + 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, + 0x19, 0xd0, 0xc0, 0x00, 0x00, 0x00, + 0x9c, 0x89, 0x40, 0x00, 0x00, 0x00, + 0xe3, 0x4c, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_6[36] = { + 0xcc, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x62, 0x80, 0x00, 0x00, 0x00, + 0xb0, 0x98, 0x40, 0x00, 0x00, 0x00, + 0x8a, 0x85, 0x40, 0x00, 0x00, 0x00, + 0x29, 0x53, 0x00, 0x00, 0x00, 0x00, + 0xa6, 0x0a, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_7[42] = { + 0x44, 0xa2, 0x40, 0x00, 0x00, 0x00, + 0x23, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x91, 0x48, 0x80, 0x00, 0x00, 0x00, + 0x0a, 0x85, 0x40, 0x00, 0x00, 0x00, + 0x34, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x06, 0x80, 0x00, 0x00, 0x00, + 0xe0, 0x64, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_8[48] = { + 0x16, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x60, 0xb0, 0x40, 0x00, 0x00, 0x00, + 0x85, 0x42, 0x80, 0x00, 0x00, 0x00, + 0x4c, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x29, 0x14, 0x80, 0x00, 0x00, 0x00, + 0x11, 0x88, 0xc0, 0x00, 0x00, 0x00, + 0xb0, 0x58, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom18_9[54] = { + 0x44, 0xa2, 0x40, 0x00, 0x00, 0x00, + 0x66, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x49, 0x40, 0x00, 0x00, 0x00, + 0x01, 0xa5, 0x80, 0x00, 0x00, 0x00, + 0x0e, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x20, 0xd0, 0x40, 0x00, 0x00, 0x00, + 0xc2, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x29, 0x0c, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_1[6] = { + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_10[60] = { + 0x8c, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x11, 0xc0, 0x00, 0x00, 0x00, + 0x32, 0x8d, 0x20, 0x00, 0x00, 0x00, + 0x61, 0x92, 0x60, 0x00, 0x00, 0x00, + 0x5c, 0x38, 0x80, 0x00, 0x00, 0x00, + 0xcc, 0x75, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x19, 0xc0, 0x00, 0x00, 0x00, + 0x32, 0xd2, 0x60, 0x00, 0x00, 0x00, + 0x25, 0x8e, 0xa0, 0x00, 0x00, 0x00, + 0x50, 0x88, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_11[66] = { + 0x8c, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x11, 0xc0, 0x00, 0x00, 0x00, + 0x32, 0x8d, 0x20, 0x00, 0x00, 0x00, + 0x61, 0x92, 0x60, 0x00, 0x00, 0x00, + 0x5c, 0x38, 0x80, 0x00, 0x00, 0x00, + 0x84, 0x87, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x51, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x22, 0xa0, 0x00, 0x00, 0x00, + 0x68, 0x44, 0x40, 0x00, 0x00, 0x00, + 0x89, 0x70, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_12[72] = { + 0x84, 0x87, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x51, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x22, 0xa0, 0x00, 0x00, 0x00, + 0x68, 0x44, 0x40, 0x00, 0x00, 0x00, + 0x89, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x8c, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x11, 0xc0, 0x00, 0x00, 0x00, + 0x32, 0x8d, 0x20, 0x00, 0x00, 0x00, + 0x61, 0x92, 0x60, 0x00, 0x00, 0x00, + 0x5c, 0x38, 0x80, 0x00, 0x00, 0x00, + 0x90, 0xc8, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_13[78] = { + 0x84, 0x87, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x51, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x22, 0xa0, 0x00, 0x00, 0x00, + 0x68, 0x44, 0x40, 0x00, 0x00, 0x00, + 0x89, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x8c, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x81, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x12, 0x86, 0x20, 0x00, 0x00, 0x00, + 0x58, 0x14, 0x40, 0x00, 0x00, 0x00, + 0x28, 0xca, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x60, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_14[84] = { + 0x8c, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x81, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x12, 0x86, 0x20, 0x00, 0x00, 0x00, + 0x58, 0x14, 0x40, 0x00, 0x00, 0x00, + 0x28, 0xca, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x60, 0x80, 0x00, 0x00, 0x00, + 0x84, 0x87, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x51, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x22, 0xa0, 0x00, 0x00, 0x00, + 0x68, 0x44, 0x40, 0x00, 0x00, 0x00, + 0x89, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x6e, 0x27, 0x60, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_15[90] = { + 0x8c, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x81, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x12, 0x86, 0x20, 0x00, 0x00, 0x00, + 0x58, 0x14, 0x40, 0x00, 0x00, 0x00, + 0x28, 0xca, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x60, 0x80, 0x00, 0x00, 0x00, + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x40, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0xd0, 0x20, 0x00, 0x00, 0x00, + 0x06, 0x82, 0xa0, 0x00, 0x00, 0x00, + 0xc8, 0x0c, 0x40, 0x00, 0x00, 0x00, + 0x45, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x91, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x28, 0x20, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_16[96] = { + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x40, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0xd0, 0x20, 0x00, 0x00, 0x00, + 0x06, 0x82, 0xa0, 0x00, 0x00, 0x00, + 0xc8, 0x0c, 0x40, 0x00, 0x00, 0x00, + 0x45, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x91, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x8c, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x81, 0x88, 0x60, 0x00, 0x00, 0x00, + 0x12, 0x86, 0x20, 0x00, 0x00, 0x00, + 0x58, 0x14, 0x40, 0x00, 0x00, 0x00, + 0x28, 0xca, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x60, 0x80, 0x00, 0x00, 0x00, + 0x7e, 0x75, 0xe0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_17[102] = { + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x40, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0xd0, 0x20, 0x00, 0x00, 0x00, + 0x06, 0x82, 0xa0, 0x00, 0x00, 0x00, + 0xc8, 0x0c, 0x40, 0x00, 0x00, 0x00, + 0x45, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x91, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x4c, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x71, 0x80, 0x00, 0x00, 0x00, + 0x91, 0x40, 0xe0, 0x00, 0x00, 0x00, + 0x42, 0x90, 0xa0, 0x00, 0x00, 0x00, + 0xa4, 0x29, 0x40, 0x00, 0x00, 0x00, + 0x13, 0x5a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x93, 0x40, 0x00, 0x00, 0x00, + 0x88, 0xac, 0x20, 0x00, 0x00, 0x00, + 0x09, 0x0c, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_18[108] = { + 0x4c, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x71, 0x80, 0x00, 0x00, 0x00, + 0x91, 0x40, 0xe0, 0x00, 0x00, 0x00, + 0x42, 0x90, 0xa0, 0x00, 0x00, 0x00, + 0xa4, 0x29, 0x40, 0x00, 0x00, 0x00, + 0x13, 0x5a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x93, 0x40, 0x00, 0x00, 0x00, + 0x88, 0xac, 0x20, 0x00, 0x00, 0x00, + 0x09, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x2c, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x91, 0x40, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0xd0, 0x20, 0x00, 0x00, 0x00, + 0x06, 0x82, 0xa0, 0x00, 0x00, 0x00, + 0xc8, 0x0c, 0x40, 0x00, 0x00, 0x00, + 0x45, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x91, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x51, 0x97, 0x20, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_19[114] = { + 0x4c, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x71, 0x80, 0x00, 0x00, 0x00, + 0x91, 0x40, 0xe0, 0x00, 0x00, 0x00, + 0x42, 0x90, 0xa0, 0x00, 0x00, 0x00, + 0xa4, 0x29, 0x40, 0x00, 0x00, 0x00, + 0x13, 0x5a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x93, 0x40, 0x00, 0x00, 0x00, + 0x88, 0xac, 0x20, 0x00, 0x00, 0x00, + 0x09, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x4c, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x28, 0x80, 0x00, 0x00, 0x00, + 0x91, 0x50, 0x20, 0x00, 0x00, 0x00, + 0x42, 0x82, 0x60, 0x00, 0x00, 0x00, + 0xa4, 0x01, 0xc0, 0x00, 0x00, 0x00, + 0x13, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x94, 0x80, 0x00, 0x00, 0x00, + 0x88, 0xa1, 0x20, 0x00, 0x00, 0x00, + 0x09, 0x4c, 0x00, 0x00, 0x00, 0x00, + 0xcd, 0x98, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_2[12] = { + 0xce, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x39, 0xcc, 0xe0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_3[18] = { + 0xcc, 0x67, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x2c, 0xc0, 0x00, 0x00, 0x00, + 0x92, 0xd2, 0x60, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_4[24] = { + 0xec, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x67, 0x19, 0xc0, 0x00, 0x00, 0x00, + 0xb1, 0xcc, 0x60, 0x00, 0x00, 0x00, + 0x5a, 0x96, 0xa0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_5[30] = { + 0x4c, 0xe7, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x31, 0xc0, 0x00, 0x00, 0x00, + 0xa1, 0xcc, 0x60, 0x00, 0x00, 0x00, + 0x92, 0xa6, 0xa0, 0x00, 0x00, 0x00, + 0xb8, 0x99, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_6[36] = { + 0x4c, 0x36, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x68, 0x80, 0x00, 0x00, 0x00, + 0x30, 0xd0, 0x60, 0x00, 0x00, 0x00, + 0x8a, 0x82, 0xa0, 0x00, 0x00, 0x00, + 0x26, 0x0b, 0x40, 0x00, 0x00, 0x00, + 0x95, 0x45, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_7[42] = { + 0xc4, 0xa3, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x19, 0x80, 0x00, 0x00, 0x00, + 0x91, 0x1c, 0x20, 0x00, 0x00, 0x00, + 0x4a, 0x82, 0xa0, 0x00, 0x00, 0x00, + 0x34, 0x49, 0x40, 0x00, 0x00, 0x00, + 0x8b, 0x4a, 0x00, 0x00, 0x00, 0x00, + 0xc8, 0x24, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_8[48] = { + 0x16, 0x13, 0x80, 0x00, 0x00, 0x00, + 0xc2, 0x44, 0xc0, 0x00, 0x00, 0x00, + 0x60, 0xe8, 0x20, 0x00, 0x00, 0x00, + 0x85, 0x12, 0x60, 0x00, 0x00, 0x00, + 0xcc, 0x21, 0x40, 0x00, 0x00, 0x00, + 0x29, 0x63, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x98, 0xc0, 0x00, 0x00, 0x00, + 0xb0, 0x0c, 0x60, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom19_9[54] = { + 0x44, 0xa7, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x70, 0x80, 0x00, 0x00, 0x00, + 0x12, 0xc0, 0xe0, 0x00, 0x00, 0x00, + 0xc3, 0x10, 0xa0, 0x00, 0x00, 0x00, + 0x8c, 0x29, 0x40, 0x00, 0x00, 0x00, + 0x11, 0x5b, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x93, 0x40, 0x00, 0x00, 0x00, + 0xa2, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x0c, 0xe0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom1_1[2] = { + 0x80, 0x00 +}; + +const uint8_t kMaskRandom20_1[6] = { + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_10[60] = { + 0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x40, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x10, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x30, 0x00, 0x00, 0x00, + 0x03, 0x80, 0xe0, 0x00, 0x00, 0x00, + 0x86, 0x21, 0x80, 0x00, 0x00, 0x00, + 0x29, 0x0a, 0x40, 0x00, 0x00, 0x00, + 0x42, 0x50, 0x90, 0x00, 0x00, 0x00, + 0x98, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x8c, 0x20, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_11[66] = { + 0xc6, 0x31, 0x80, 0x00, 0x00, 0x00, + 0x23, 0x88, 0xe0, 0x00, 0x00, 0x00, + 0x1a, 0x46, 0x90, 0x00, 0x00, 0x00, + 0x24, 0xc9, 0x30, 0x00, 0x00, 0x00, + 0x71, 0x1c, 0x40, 0x00, 0x00, 0x00, + 0x0e, 0x03, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x45, 0x51, 0x50, 0x00, 0x00, 0x00, + 0x88, 0xa2, 0x20, 0x00, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_12[72] = { + 0x0e, 0x03, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x45, 0x51, 0x50, 0x00, 0x00, 0x00, + 0x88, 0xa2, 0x20, 0x00, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x00, 0x00, + 0xc6, 0x31, 0x80, 0x00, 0x00, 0x00, + 0x23, 0x88, 0xe0, 0x00, 0x00, 0x00, + 0x1a, 0x46, 0x90, 0x00, 0x00, 0x00, + 0x24, 0xc9, 0x30, 0x00, 0x00, 0x00, + 0x71, 0x1c, 0x40, 0x00, 0x00, 0x00, + 0xf5, 0xdc, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_13[78] = { + 0x0e, 0x03, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x45, 0x51, 0x50, 0x00, 0x00, 0x00, + 0x88, 0xa2, 0x20, 0x00, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x0c, 0x43, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x8a, 0x20, 0x00, 0x00, 0x00, + 0x94, 0x25, 0x00, 0x00, 0x00, 0x00, + 0xc1, 0x30, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_14[84] = { + 0x46, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x0c, 0x43, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x8a, 0x20, 0x00, 0x00, 0x00, + 0x94, 0x25, 0x00, 0x00, 0x00, 0x00, + 0xc1, 0x30, 0x40, 0x00, 0x00, 0x00, + 0x0e, 0x03, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x45, 0x51, 0x50, 0x00, 0x00, 0x00, + 0x88, 0xa2, 0x20, 0x00, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x3e, 0x20, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_15[90] = { + 0x46, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x0c, 0x43, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x8a, 0x20, 0x00, 0x00, 0x00, + 0x94, 0x25, 0x00, 0x00, 0x00, 0x00, + 0xc1, 0x30, 0x40, 0x00, 0x00, 0x00, + 0x2c, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x60, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x86, 0x20, 0x00, 0x00, 0x00, + 0xc2, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x88, 0xa0, 0x00, 0x00, 0x00, + 0x50, 0x54, 0x10, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_16[96] = { + 0x2c, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x60, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x86, 0x20, 0x00, 0x00, 0x00, + 0xc2, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x88, 0xa0, 0x00, 0x00, 0x00, + 0x50, 0x54, 0x10, 0x00, 0x00, 0x00, + 0x46, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc0, 0x00, 0x00, 0x00, + 0x10, 0xc4, 0x30, 0x00, 0x00, 0x00, + 0x0c, 0x43, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x8a, 0x20, 0x00, 0x00, 0x00, + 0x94, 0x25, 0x00, 0x00, 0x00, 0x00, + 0xc1, 0x30, 0x40, 0x00, 0x00, 0x00, + 0x28, 0x1c, 0x60, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_17[102] = { + 0x2c, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x60, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x86, 0x20, 0x00, 0x00, 0x00, + 0xc2, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x88, 0xa0, 0x00, 0x00, 0x00, + 0x50, 0x54, 0x10, 0x00, 0x00, 0x00, + 0x4e, 0x13, 0x80, 0x00, 0x00, 0x00, + 0xe3, 0x38, 0xc0, 0x00, 0x00, 0x00, + 0x81, 0xe0, 0x70, 0x00, 0x00, 0x00, + 0x21, 0x48, 0x50, 0x00, 0x00, 0x00, + 0x52, 0x94, 0xa0, 0x00, 0x00, 0x00, + 0xb4, 0x2d, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x89, 0xa0, 0x00, 0x00, 0x00, + 0x58, 0x56, 0x10, 0x00, 0x00, 0x00, + 0x19, 0x86, 0x60, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_18[108] = { + 0x4e, 0x13, 0x80, 0x00, 0x00, 0x00, + 0xe3, 0x38, 0xc0, 0x00, 0x00, 0x00, + 0x81, 0xe0, 0x70, 0x00, 0x00, 0x00, + 0x21, 0x48, 0x50, 0x00, 0x00, 0x00, + 0x52, 0x94, 0xa0, 0x00, 0x00, 0x00, + 0xb4, 0x2d, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x89, 0xa0, 0x00, 0x00, 0x00, + 0x58, 0x56, 0x10, 0x00, 0x00, 0x00, + 0x19, 0x86, 0x60, 0x00, 0x00, 0x00, + 0x2c, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x60, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x86, 0x20, 0x00, 0x00, 0x00, + 0xc2, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x88, 0xa0, 0x00, 0x00, 0x00, + 0x50, 0x54, 0x10, 0x00, 0x00, 0x00, + 0x21, 0x7b, 0xf0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_19[114] = { + 0x4e, 0x13, 0x80, 0x00, 0x00, 0x00, + 0xe3, 0x38, 0xc0, 0x00, 0x00, 0x00, + 0x81, 0xe0, 0x70, 0x00, 0x00, 0x00, + 0x21, 0x48, 0x50, 0x00, 0x00, 0x00, + 0x52, 0x94, 0xa0, 0x00, 0x00, 0x00, + 0xb4, 0x2d, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x89, 0xa0, 0x00, 0x00, 0x00, + 0x58, 0x56, 0x10, 0x00, 0x00, 0x00, + 0x19, 0x86, 0x60, 0x00, 0x00, 0x00, + 0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x40, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x10, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x30, 0x00, 0x00, 0x00, + 0x03, 0x80, 0xe0, 0x00, 0x00, 0x00, + 0x86, 0x21, 0x80, 0x00, 0x00, 0x00, + 0x29, 0x0a, 0x40, 0x00, 0x00, 0x00, + 0x42, 0x50, 0x90, 0x00, 0x00, 0x00, + 0x98, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x8c, 0x20, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_2[12] = { + 0xee, 0x3b, 0x80, 0x00, 0x00, 0x00, + 0x99, 0xe6, 0x70, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_20[120] = { + 0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x40, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x10, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x30, 0x00, 0x00, 0x00, + 0x03, 0x80, 0xe0, 0x00, 0x00, 0x00, + 0x86, 0x21, 0x80, 0x00, 0x00, 0x00, + 0x29, 0x0a, 0x40, 0x00, 0x00, 0x00, + 0x42, 0x50, 0x90, 0x00, 0x00, 0x00, + 0x98, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x8c, 0x20, 0x00, 0x00, 0x00, + 0x4e, 0x13, 0x80, 0x00, 0x00, 0x00, + 0xe3, 0x38, 0xc0, 0x00, 0x00, 0x00, + 0x81, 0xe0, 0x70, 0x00, 0x00, 0x00, + 0x21, 0x48, 0x50, 0x00, 0x00, 0x00, + 0x52, 0x94, 0xa0, 0x00, 0x00, 0x00, + 0xb4, 0x2d, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x89, 0xa0, 0x00, 0x00, 0x00, + 0x58, 0x56, 0x10, 0x00, 0x00, 0x00, + 0x19, 0x86, 0x60, 0x00, 0x00, 0x00, + 0xf7, 0x8d, 0xa0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_3[18] = { + 0xce, 0x33, 0x80, 0x00, 0x00, 0x00, + 0x55, 0x95, 0x60, 0x00, 0x00, 0x00, + 0xb1, 0x6a, 0x30, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_4[24] = { + 0xe6, 0x39, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x8c, 0xe0, 0x00, 0x00, 0x00, + 0x98, 0xe6, 0x30, 0x00, 0x00, 0x00, + 0x2d, 0x4b, 0x50, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_5[30] = { + 0xce, 0x33, 0x80, 0x00, 0x00, 0x00, + 0x63, 0x98, 0xe0, 0x00, 0x00, 0x00, + 0x98, 0xe5, 0x30, 0x00, 0x00, 0x00, + 0x2b, 0x53, 0x50, 0x00, 0x00, 0x00, + 0xb4, 0x5c, 0xa0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_6[36] = { + 0x4c, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x34, 0x40, 0x00, 0x00, 0x00, + 0x20, 0xe8, 0x30, 0x00, 0x00, 0x00, + 0x85, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x06, 0x86, 0xa0, 0x00, 0x00, 0x00, + 0x9a, 0x21, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_7[42] = { + 0x4e, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x33, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x0e, 0xb0, 0x00, 0x00, 0x00, + 0x81, 0x51, 0x50, 0x00, 0x00, 0x00, + 0x24, 0xc4, 0xa0, 0x00, 0x00, 0x00, + 0xd4, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0xa2, 0x60, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_8[48] = { + 0x27, 0x09, 0xc0, 0x00, 0x00, 0x00, + 0x89, 0xa2, 0x60, 0x00, 0x00, 0x00, + 0xd0, 0x74, 0x10, 0x00, 0x00, 0x00, + 0x24, 0xc9, 0x30, 0x00, 0x00, 0x00, + 0xe2, 0x90, 0xa0, 0x00, 0x00, 0x00, + 0xc6, 0x31, 0x80, 0x00, 0x00, 0x00, + 0x31, 0x8c, 0x60, 0x00, 0x00, 0x00, + 0x18, 0xc6, 0x30, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom20_9[54] = { + 0x4e, 0x13, 0x80, 0x00, 0x00, 0x00, + 0x62, 0x38, 0xc0, 0x00, 0x00, 0x00, + 0x81, 0xe0, 0x70, 0x00, 0x00, 0x00, + 0xe1, 0x48, 0x50, 0x00, 0x00, 0x00, + 0x13, 0x94, 0xa0, 0x00, 0x00, 0x00, + 0xb4, 0x2d, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x89, 0xa0, 0x00, 0x00, 0x00, + 0x58, 0x56, 0x10, 0x00, 0x00, 0x00, + 0x49, 0x86, 0x50, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_1[6] = { + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_10[60] = { + 0x4c, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x50, 0x00, 0x00, 0x00, + 0xa0, 0x6a, 0x40, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x30, 0x00, 0x00, 0x00, + 0x03, 0xb4, 0x00, 0x00, 0x00, 0x00, + 0x86, 0x20, 0x90, 0x00, 0x00, 0x00, + 0x29, 0x08, 0x48, 0x00, 0x00, 0x00, + 0x42, 0x43, 0x08, 0x00, 0x00, 0x00, + 0x98, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x84, 0xa8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_11[66] = { + 0xc6, 0x21, 0xa0, 0x00, 0x00, 0x00, + 0x23, 0x88, 0xc8, 0x00, 0x00, 0x00, + 0x1a, 0x45, 0x88, 0x00, 0x00, 0x00, + 0x24, 0xd3, 0x08, 0x00, 0x00, 0x00, + 0x71, 0x10, 0x70, 0x00, 0x00, 0x00, + 0x0e, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x33, 0x14, 0x50, 0x00, 0x00, 0x00, + 0x10, 0xc3, 0x28, 0x00, 0x00, 0x00, + 0x45, 0x68, 0x48, 0x00, 0x00, 0x00, + 0x88, 0x84, 0xa8, 0x00, 0x00, 0x00, + 0xe0, 0x22, 0x90, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_12[72] = { + 0x0e, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x33, 0x14, 0x50, 0x00, 0x00, 0x00, + 0x10, 0xc3, 0x28, 0x00, 0x00, 0x00, + 0x45, 0x68, 0x48, 0x00, 0x00, 0x00, + 0x88, 0x84, 0xa8, 0x00, 0x00, 0x00, + 0xe0, 0x22, 0x90, 0x00, 0x00, 0x00, + 0xc6, 0x21, 0xa0, 0x00, 0x00, 0x00, + 0x23, 0x88, 0xc8, 0x00, 0x00, 0x00, + 0x1a, 0x45, 0x88, 0x00, 0x00, 0x00, + 0x24, 0xd3, 0x08, 0x00, 0x00, 0x00, + 0x71, 0x10, 0x70, 0x00, 0x00, 0x00, + 0xa0, 0x65, 0x18, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_13[78] = { + 0x0e, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x33, 0x14, 0x50, 0x00, 0x00, 0x00, + 0x10, 0xc3, 0x28, 0x00, 0x00, 0x00, + 0x45, 0x68, 0x48, 0x00, 0x00, 0x00, + 0x88, 0x84, 0xa8, 0x00, 0x00, 0x00, + 0xe0, 0x22, 0x90, 0x00, 0x00, 0x00, + 0x46, 0x11, 0x90, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc8, 0x00, 0x00, 0x00, + 0x10, 0xe4, 0x60, 0x00, 0x00, 0x00, + 0x0c, 0x69, 0x08, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x28, 0x00, 0x00, 0x00, + 0x94, 0x21, 0x30, 0x00, 0x00, 0x00, + 0xc1, 0x02, 0x58, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_14[84] = { + 0x46, 0x11, 0x90, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc8, 0x00, 0x00, 0x00, + 0x10, 0xe4, 0x60, 0x00, 0x00, 0x00, + 0x0c, 0x69, 0x08, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x28, 0x00, 0x00, 0x00, + 0x94, 0x21, 0x30, 0x00, 0x00, 0x00, + 0xc1, 0x02, 0x58, 0x00, 0x00, 0x00, + 0x0e, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x33, 0x14, 0x50, 0x00, 0x00, 0x00, + 0x10, 0xc3, 0x28, 0x00, 0x00, 0x00, + 0x45, 0x68, 0x48, 0x00, 0x00, 0x00, + 0x88, 0x84, 0xa8, 0x00, 0x00, 0x00, + 0xe0, 0x22, 0x90, 0x00, 0x00, 0x00, + 0x4d, 0xd0, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_15[90] = { + 0x46, 0x11, 0x90, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc8, 0x00, 0x00, 0x00, + 0x10, 0xe4, 0x60, 0x00, 0x00, 0x00, + 0x0c, 0x69, 0x08, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x28, 0x00, 0x00, 0x00, + 0x94, 0x21, 0x30, 0x00, 0x00, 0x00, + 0xc1, 0x02, 0x58, 0x00, 0x00, 0x00, + 0x2c, 0x03, 0x20, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x18, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x20, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0xc2, 0x06, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x98, 0x08, 0x00, 0x00, 0x00, + 0x50, 0x45, 0x08, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_16[96] = { + 0x2c, 0x03, 0x20, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x18, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x20, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0xc2, 0x06, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x98, 0x08, 0x00, 0x00, 0x00, + 0x50, 0x45, 0x08, 0x00, 0x00, 0x00, + 0x46, 0x11, 0x90, 0x00, 0x00, 0x00, + 0x33, 0x0c, 0xc8, 0x00, 0x00, 0x00, + 0x10, 0xe4, 0x60, 0x00, 0x00, 0x00, + 0x0c, 0x69, 0x08, 0x00, 0x00, 0x00, + 0x28, 0x94, 0x28, 0x00, 0x00, 0x00, + 0x94, 0x21, 0x30, 0x00, 0x00, 0x00, + 0xc1, 0x02, 0x58, 0x00, 0x00, 0x00, + 0x3b, 0xf5, 0x38, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_17[102] = { + 0x2c, 0x03, 0x20, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x18, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x20, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0xc2, 0x06, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x98, 0x08, 0x00, 0x00, 0x00, + 0x50, 0x45, 0x08, 0x00, 0x00, 0x00, + 0x4e, 0x11, 0x90, 0x00, 0x00, 0x00, + 0xe3, 0x18, 0x98, 0x00, 0x00, 0x00, + 0x81, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x40, 0x58, 0x00, 0x00, 0x00, + 0x52, 0x81, 0xe0, 0x00, 0x00, 0x00, + 0xb4, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x26, 0x86, 0x28, 0x00, 0x00, 0x00, + 0x58, 0x64, 0x40, 0x00, 0x00, 0x00, + 0x19, 0x9e, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_18[108] = { + 0x4e, 0x11, 0x90, 0x00, 0x00, 0x00, + 0xe3, 0x18, 0x98, 0x00, 0x00, 0x00, + 0x81, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x40, 0x58, 0x00, 0x00, 0x00, + 0x52, 0x81, 0xe0, 0x00, 0x00, 0x00, + 0xb4, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x26, 0x86, 0x28, 0x00, 0x00, 0x00, + 0x58, 0x64, 0x40, 0x00, 0x00, 0x00, + 0x19, 0x9e, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x03, 0x20, 0x00, 0x00, 0x00, + 0x81, 0xa0, 0x18, 0x00, 0x00, 0x00, + 0xa0, 0x68, 0x20, 0x00, 0x00, 0x00, + 0x05, 0x41, 0x50, 0x00, 0x00, 0x00, + 0x18, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0xc2, 0x06, 0x80, 0x00, 0x00, 0x00, + 0x22, 0x98, 0x08, 0x00, 0x00, 0x00, + 0x50, 0x45, 0x08, 0x00, 0x00, 0x00, + 0x5a, 0x56, 0x58, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_19[114] = { + 0x4e, 0x11, 0x90, 0x00, 0x00, 0x00, + 0xe3, 0x18, 0x98, 0x00, 0x00, 0x00, + 0x81, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x40, 0x58, 0x00, 0x00, 0x00, + 0x52, 0x81, 0xe0, 0x00, 0x00, 0x00, + 0xb4, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x26, 0x86, 0x28, 0x00, 0x00, 0x00, + 0x58, 0x64, 0x40, 0x00, 0x00, 0x00, + 0x19, 0x9e, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x50, 0x00, 0x00, 0x00, + 0xa0, 0x6a, 0x40, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x30, 0x00, 0x00, 0x00, + 0x03, 0xb4, 0x00, 0x00, 0x00, 0x00, + 0x86, 0x20, 0x90, 0x00, 0x00, 0x00, + 0x29, 0x08, 0x48, 0x00, 0x00, 0x00, + 0x42, 0x43, 0x08, 0x00, 0x00, 0x00, + 0x98, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x84, 0xa8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_2[12] = { + 0xee, 0x3b, 0x30, 0x00, 0x00, 0x00, + 0x99, 0xe6, 0xe8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_20[120] = { + 0x4c, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x50, 0x00, 0x00, 0x00, + 0xa0, 0x6a, 0x40, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x30, 0x00, 0x00, 0x00, + 0x03, 0xb4, 0x00, 0x00, 0x00, 0x00, + 0x86, 0x20, 0x90, 0x00, 0x00, 0x00, + 0x29, 0x08, 0x48, 0x00, 0x00, 0x00, + 0x42, 0x43, 0x08, 0x00, 0x00, 0x00, + 0x98, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x84, 0xa8, 0x00, 0x00, 0x00, + 0x4e, 0x11, 0x90, 0x00, 0x00, 0x00, + 0xe3, 0x18, 0x98, 0x00, 0x00, 0x00, + 0x81, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x40, 0x58, 0x00, 0x00, 0x00, + 0x52, 0x81, 0xe0, 0x00, 0x00, 0x00, + 0xb4, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x26, 0x86, 0x28, 0x00, 0x00, 0x00, + 0x58, 0x64, 0x40, 0x00, 0x00, 0x00, + 0x19, 0x9e, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x03, 0x30, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_21[126] = { + 0x4c, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x50, 0x00, 0x00, 0x00, + 0xa0, 0x6a, 0x40, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x30, 0x00, 0x00, 0x00, + 0x03, 0xb4, 0x00, 0x00, 0x00, 0x00, + 0x86, 0x20, 0x90, 0x00, 0x00, 0x00, + 0x29, 0x08, 0x48, 0x00, 0x00, 0x00, + 0x42, 0x43, 0x08, 0x00, 0x00, 0x00, + 0x98, 0x12, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x84, 0xa8, 0x00, 0x00, 0x00, + 0x4c, 0x11, 0x90, 0x00, 0x00, 0x00, + 0x51, 0x0c, 0xc8, 0x00, 0x00, 0x00, + 0xa0, 0x66, 0x40, 0x00, 0x00, 0x00, + 0x04, 0xc1, 0x60, 0x00, 0x00, 0x00, + 0x03, 0xa0, 0x28, 0x00, 0x00, 0x00, + 0x86, 0x21, 0x10, 0x00, 0x00, 0x00, + 0x29, 0x10, 0x18, 0x00, 0x00, 0x00, + 0x42, 0x42, 0xa0, 0x00, 0x00, 0x00, + 0x98, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x84, 0x08, 0x00, 0x00, 0x00, + 0xdf, 0x4c, 0x10, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_3[18] = { + 0xce, 0x32, 0xb0, 0x00, 0x00, 0x00, + 0x55, 0xdc, 0x50, 0x00, 0x00, 0x00, + 0xa8, 0xed, 0x88, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_4[24] = { + 0xe6, 0x31, 0x30, 0x00, 0x00, 0x00, + 0x33, 0x8c, 0x58, 0x00, 0x00, 0x00, + 0x98, 0xd2, 0xc8, 0x00, 0x00, 0x00, + 0x2d, 0x4b, 0x28, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_5[30] = { + 0xce, 0x31, 0xb0, 0x00, 0x00, 0x00, + 0x63, 0x98, 0xd8, 0x00, 0x00, 0x00, + 0x98, 0xc7, 0x68, 0x00, 0x00, 0x00, + 0x4d, 0x6b, 0x50, 0x00, 0x00, 0x00, + 0xb2, 0x6c, 0xa8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_6[36] = { + 0x4c, 0x19, 0x10, 0x00, 0x00, 0x00, + 0x51, 0x14, 0x50, 0x00, 0x00, 0x00, + 0x20, 0xea, 0x08, 0x00, 0x00, 0x00, + 0x85, 0x41, 0x28, 0x00, 0x00, 0x00, + 0x06, 0x80, 0xd8, 0x00, 0x00, 0x00, + 0x8a, 0x24, 0x30, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_7[42] = { + 0xc6, 0x11, 0x90, 0x00, 0x00, 0x00, + 0x33, 0x04, 0xc8, 0x00, 0x00, 0x00, + 0x18, 0x67, 0x40, 0x00, 0x00, 0x00, + 0x45, 0x42, 0xd0, 0x00, 0x00, 0x00, + 0x12, 0xd4, 0x28, 0x00, 0x00, 0x00, + 0xb4, 0x28, 0x30, 0x00, 0x00, 0x00, + 0x29, 0x92, 0x18, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_8[48] = { + 0x07, 0x0a, 0x70, 0x00, 0x00, 0x00, + 0x49, 0xa8, 0x28, 0x00, 0x00, 0x00, + 0xb0, 0x7a, 0x00, 0x00, 0x00, 0x00, + 0x24, 0xc5, 0xc0, 0x00, 0x00, 0x00, + 0x52, 0x80, 0xe8, 0x00, 0x00, 0x00, + 0xc6, 0x31, 0x80, 0x00, 0x00, 0x00, + 0x31, 0x94, 0x18, 0x00, 0x00, 0x00, + 0x18, 0xc7, 0x08, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom21_9[54] = { + 0x4e, 0x11, 0x10, 0x00, 0x00, 0x00, + 0x62, 0x1a, 0x08, 0x00, 0x00, 0x00, + 0x80, 0xe9, 0x40, 0x00, 0x00, 0x00, + 0xa1, 0x50, 0x50, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x68, 0x00, 0x00, 0x00, + 0xa4, 0x24, 0x30, 0x00, 0x00, 0x00, + 0x16, 0xa0, 0x88, 0x00, 0x00, 0x00, + 0x58, 0x45, 0x20, 0x00, 0x00, 0x00, + 0x29, 0x86, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_1[6] = { + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_10[60] = { + 0xc0, 0x38, 0x88, 0x00, 0x00, 0x00, + 0x30, 0x0e, 0x28, 0x00, 0x00, 0x00, + 0xe8, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x85, 0x08, 0xa8, 0x00, 0x00, 0x00, + 0xd0, 0x92, 0x10, 0x00, 0x00, 0x00, + 0x86, 0x50, 0x48, 0x00, 0x00, 0x00, + 0x4a, 0x68, 0x0c, 0x00, 0x00, 0x00, + 0x01, 0xa0, 0x74, 0x00, 0x00, 0x00, + 0x4c, 0x81, 0x90, 0x00, 0x00, 0x00, + 0x62, 0x24, 0x04, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_11[66] = { + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x99, 0x13, 0x20, 0x00, 0x00, 0x00, + 0x05, 0x80, 0xb0, 0x00, 0x00, 0x00, + 0x80, 0xb0, 0x14, 0x00, 0x00, 0x00, + 0x84, 0x50, 0x88, 0x00, 0x00, 0x00, + 0x40, 0x68, 0x0c, 0x00, 0x00, 0x00, + 0x0a, 0x81, 0x50, 0x00, 0x00, 0x00, + 0x68, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x22, 0x04, 0x00, 0x00, 0x00, + 0x30, 0x46, 0x08, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_12[72] = { + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x0c, 0xa1, 0x94, 0x00, 0x00, 0x00, + 0xa1, 0x34, 0x24, 0x00, 0x00, 0x00, + 0x12, 0xa2, 0x54, 0x00, 0x00, 0x00, + 0x8a, 0x51, 0x48, 0x00, 0x00, 0x00, + 0x86, 0x90, 0xd0, 0x00, 0x00, 0x00, + 0x23, 0x24, 0x64, 0x00, 0x00, 0x00, + 0x16, 0x22, 0xc4, 0x00, 0x00, 0x00, + 0x4c, 0x29, 0x84, 0x00, 0x00, 0x00, + 0x41, 0xc8, 0x38, 0x00, 0x00, 0x00, + 0xf4, 0x18, 0x9c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_13[78] = { + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x0c, 0xa1, 0x94, 0x00, 0x00, 0x00, + 0xa1, 0x34, 0x24, 0x00, 0x00, 0x00, + 0x12, 0xa2, 0x54, 0x00, 0x00, 0x00, + 0x8a, 0x51, 0x48, 0x00, 0x00, 0x00, + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x30, 0x00, 0x00, 0x00, + 0xa4, 0x34, 0x84, 0x00, 0x00, 0x00, + 0x50, 0xaa, 0x14, 0x00, 0x00, 0x00, + 0x84, 0xd0, 0x98, 0x00, 0x00, 0x00, + 0x09, 0x61, 0x2c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_14[84] = { + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x30, 0x00, 0x00, 0x00, + 0xa4, 0x34, 0x84, 0x00, 0x00, 0x00, + 0x50, 0xaa, 0x14, 0x00, 0x00, 0x00, + 0x84, 0xd0, 0x98, 0x00, 0x00, 0x00, + 0x09, 0x61, 0x2c, 0x00, 0x00, 0x00, + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x0c, 0xa1, 0x94, 0x00, 0x00, 0x00, + 0xa1, 0x34, 0x24, 0x00, 0x00, 0x00, + 0x12, 0xa2, 0x54, 0x00, 0x00, 0x00, + 0x8a, 0x51, 0x48, 0x00, 0x00, 0x00, + 0xc6, 0xca, 0xe8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_15[90] = { + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x30, 0x00, 0x00, 0x00, + 0xa4, 0x34, 0x84, 0x00, 0x00, 0x00, + 0x50, 0xaa, 0x14, 0x00, 0x00, 0x00, + 0x84, 0xd0, 0x98, 0x00, 0x00, 0x00, + 0x09, 0x61, 0x2c, 0x00, 0x00, 0x00, + 0x0c, 0x81, 0x90, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x0c, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x40, 0xa8, 0x00, 0x00, 0x00, + 0x43, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x40, 0x00, 0x00, 0x00, + 0x60, 0x2c, 0x04, 0x00, 0x00, 0x00, + 0x14, 0x22, 0x84, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_16[96] = { + 0x0c, 0x81, 0x90, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x0c, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x40, 0xa8, 0x00, 0x00, 0x00, + 0x43, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x40, 0x00, 0x00, 0x00, + 0x60, 0x2c, 0x04, 0x00, 0x00, 0x00, + 0x14, 0x22, 0x84, 0x00, 0x00, 0x00, + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x30, 0x00, 0x00, 0x00, + 0xa4, 0x34, 0x84, 0x00, 0x00, 0x00, + 0x50, 0xaa, 0x14, 0x00, 0x00, 0x00, + 0x84, 0xd0, 0x98, 0x00, 0x00, 0x00, + 0x09, 0x61, 0x2c, 0x00, 0x00, 0x00, + 0x86, 0xc1, 0x44, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_17[102] = { + 0x0c, 0x81, 0x90, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x0c, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x40, 0xa8, 0x00, 0x00, 0x00, + 0x43, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x40, 0x00, 0x00, 0x00, + 0x60, 0x2c, 0x04, 0x00, 0x00, 0x00, + 0x14, 0x22, 0x84, 0x00, 0x00, 0x00, + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x62, 0x6c, 0x4c, 0x00, 0x00, 0x00, + 0x8c, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x01, 0x60, 0x2c, 0x00, 0x00, 0x00, + 0x07, 0x80, 0xf0, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x18, 0xa3, 0x14, 0x00, 0x00, 0x00, + 0x91, 0x12, 0x20, 0x00, 0x00, 0x00, + 0x78, 0x0f, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_18[108] = { + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x62, 0x6c, 0x4c, 0x00, 0x00, 0x00, + 0x8c, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x01, 0x60, 0x2c, 0x00, 0x00, 0x00, + 0x07, 0x80, 0xf0, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x18, 0xa3, 0x14, 0x00, 0x00, 0x00, + 0x91, 0x12, 0x20, 0x00, 0x00, 0x00, + 0x78, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x81, 0x90, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x0c, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x40, 0xa8, 0x00, 0x00, 0x00, + 0x43, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x40, 0x00, 0x00, 0x00, + 0x60, 0x2c, 0x04, 0x00, 0x00, 0x00, + 0x14, 0x22, 0x84, 0x00, 0x00, 0x00, + 0xe4, 0xd4, 0x6c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_19[114] = { + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x62, 0x6c, 0x4c, 0x00, 0x00, 0x00, + 0x8c, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x01, 0x60, 0x2c, 0x00, 0x00, 0x00, + 0x07, 0x80, 0xf0, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x18, 0xa3, 0x14, 0x00, 0x00, 0x00, + 0x91, 0x12, 0x20, 0x00, 0x00, 0x00, + 0x78, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0xa9, 0x15, 0x20, 0x00, 0x00, 0x00, + 0x04, 0xc0, 0x98, 0x00, 0x00, 0x00, + 0xd0, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x50, 0x48, 0x00, 0x00, 0x00, + 0x21, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x84, 0x00, 0x00, 0x00, + 0x4a, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x12, 0xa2, 0x54, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_2[12] = { + 0xec, 0xdd, 0x98, 0x00, 0x00, 0x00, + 0x9b, 0xb3, 0x74, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_20[120] = { + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0xa9, 0x15, 0x20, 0x00, 0x00, 0x00, + 0x04, 0xc0, 0x98, 0x00, 0x00, 0x00, + 0xd0, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x50, 0x48, 0x00, 0x00, 0x00, + 0x21, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x84, 0x00, 0x00, 0x00, + 0x4a, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x12, 0xa2, 0x54, 0x00, 0x00, 0x00, + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x62, 0x6c, 0x4c, 0x00, 0x00, 0x00, + 0x8c, 0x11, 0x80, 0x00, 0x00, 0x00, + 0x01, 0x60, 0x2c, 0x00, 0x00, 0x00, + 0x07, 0x80, 0xf0, 0x00, 0x00, 0x00, + 0xa0, 0x94, 0x10, 0x00, 0x00, 0x00, + 0x18, 0xa3, 0x14, 0x00, 0x00, 0x00, + 0x91, 0x12, 0x20, 0x00, 0x00, 0x00, + 0x78, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x3b, 0x48, 0xc4, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_21[126] = { + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0xa9, 0x15, 0x20, 0x00, 0x00, 0x00, + 0x04, 0xc0, 0x98, 0x00, 0x00, 0x00, + 0xd0, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x50, 0x48, 0x00, 0x00, 0x00, + 0x21, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x84, 0x00, 0x00, 0x00, + 0x4a, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x12, 0xa2, 0x54, 0x00, 0x00, 0x00, + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x99, 0x13, 0x20, 0x00, 0x00, 0x00, + 0x05, 0x80, 0xb0, 0x00, 0x00, 0x00, + 0x80, 0xb0, 0x14, 0x00, 0x00, 0x00, + 0x84, 0x50, 0x88, 0x00, 0x00, 0x00, + 0x40, 0x68, 0x0c, 0x00, 0x00, 0x00, + 0x0a, 0x81, 0x50, 0x00, 0x00, 0x00, + 0x68, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x22, 0x04, 0x00, 0x00, 0x00, + 0x30, 0x46, 0x08, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_22[132] = { + 0x46, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x99, 0x13, 0x20, 0x00, 0x00, 0x00, + 0x05, 0x80, 0xb0, 0x00, 0x00, 0x00, + 0x80, 0xb0, 0x14, 0x00, 0x00, 0x00, + 0x84, 0x50, 0x88, 0x00, 0x00, 0x00, + 0x40, 0x68, 0x0c, 0x00, 0x00, 0x00, + 0x0a, 0x81, 0x50, 0x00, 0x00, 0x00, + 0x68, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x22, 0x04, 0x00, 0x00, 0x00, + 0x30, 0x46, 0x08, 0x00, 0x00, 0x00, + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0xa9, 0x15, 0x20, 0x00, 0x00, 0x00, + 0x04, 0xc0, 0x98, 0x00, 0x00, 0x00, + 0xd0, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x50, 0x48, 0x00, 0x00, 0x00, + 0x21, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x84, 0x00, 0x00, 0x00, + 0x4a, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x12, 0xa2, 0x54, 0x00, 0x00, 0x00, + 0x9e, 0xce, 0x88, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_3[18] = { + 0xca, 0xd9, 0x58, 0x00, 0x00, 0x00, + 0xf1, 0x5e, 0x28, 0x00, 0x00, 0x00, + 0xb6, 0x35, 0xc4, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_4[24] = { + 0xc4, 0xd8, 0x98, 0x00, 0x00, 0x00, + 0x31, 0x66, 0x2c, 0x00, 0x00, 0x00, + 0x4b, 0x29, 0x64, 0x00, 0x00, 0x00, + 0x2c, 0xa5, 0x94, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_5[30] = { + 0xc6, 0xd8, 0xd8, 0x00, 0x00, 0x00, + 0x63, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x1d, 0xa3, 0xb4, 0x00, 0x00, 0x00, + 0xad, 0x55, 0xa8, 0x00, 0x00, 0x00, + 0xb2, 0xb6, 0x54, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_6[36] = { + 0x64, 0x4c, 0x88, 0x00, 0x00, 0x00, + 0x51, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0xa8, 0x35, 0x04, 0x00, 0x00, 0x00, + 0xc4, 0xa0, 0x94, 0x00, 0x00, 0x00, + 0x03, 0x60, 0x6c, 0x00, 0x00, 0x00, + 0x90, 0xd2, 0x18, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_7[42] = { + 0xc6, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x13, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x8d, 0x13, 0xa0, 0x00, 0x00, 0x00, + 0x8b, 0x41, 0x68, 0x00, 0x00, 0x00, + 0x52, 0xaa, 0x14, 0x00, 0x00, 0x00, + 0xa2, 0xd4, 0x18, 0x00, 0x00, 0x00, + 0x61, 0xa8, 0x2c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_8[48] = { + 0x28, 0x85, 0x38, 0x00, 0x00, 0x00, + 0x21, 0xf4, 0x04, 0x00, 0x00, 0x00, + 0xe9, 0x1d, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x02, 0xe0, 0x00, 0x00, 0x00, + 0x83, 0xa0, 0x54, 0x00, 0x00, 0x00, + 0x46, 0x18, 0xe8, 0x00, 0x00, 0x00, + 0x50, 0x6a, 0x0c, 0x00, 0x00, 0x00, + 0x1c, 0x23, 0x84, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom22_9[54] = { + 0x44, 0x48, 0xc8, 0x00, 0x00, 0x00, + 0x28, 0x2d, 0x0c, 0x00, 0x00, 0x00, + 0x25, 0x14, 0xa0, 0x00, 0x00, 0x00, + 0x59, 0x0a, 0x20, 0x00, 0x00, 0x00, + 0x03, 0xa0, 0x34, 0x00, 0x00, 0x00, + 0xc0, 0xd0, 0x18, 0x00, 0x00, 0x00, + 0xa2, 0x30, 0x44, 0x00, 0x00, 0x00, + 0x14, 0x82, 0xd0, 0x00, 0x00, 0x00, + 0x9a, 0x03, 0x80, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_1[6] = { + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_10[60] = { + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x48, 0xa2, 0x00, 0x00, 0x00, + 0xa9, 0x10, 0x1a, 0x00, 0x00, 0x00, + 0x04, 0xc4, 0x84, 0x00, 0x00, 0x00, + 0xd0, 0x01, 0x44, 0x00, 0x00, 0x00, + 0x82, 0x40, 0x1c, 0x00, 0x00, 0x00, + 0x21, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x22, 0x00, 0x00, 0x00, + 0x4a, 0x0a, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0xb4, 0x50, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_11[66] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x99, 0x02, 0x12, 0x00, 0x00, 0x00, + 0x05, 0x80, 0x0e, 0x00, 0x00, 0x00, + 0x80, 0xa1, 0x82, 0x00, 0x00, 0x00, + 0x84, 0x48, 0x18, 0x00, 0x00, 0x00, + 0x40, 0x6d, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0x68, 0x04, 0x90, 0x00, 0x00, 0x00, + 0x10, 0x31, 0x20, 0x00, 0x00, 0x00, + 0x30, 0x58, 0x04, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_12[72] = { + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x58, 0xa2, 0x00, 0x00, 0x00, + 0x0c, 0xa4, 0x30, 0x00, 0x00, 0x00, + 0xa1, 0x22, 0x46, 0x00, 0x00, 0x00, + 0x12, 0xa1, 0x1c, 0x00, 0x00, 0x00, + 0x8a, 0x45, 0xc0, 0x00, 0x00, 0x00, + 0x86, 0x8a, 0x6c, 0x00, 0x00, 0x00, + 0x23, 0x2c, 0x84, 0x00, 0x00, 0x00, + 0x16, 0x21, 0x98, 0x00, 0x00, 0x00, + 0x4c, 0x30, 0x54, 0x00, 0x00, 0x00, + 0x41, 0xc1, 0x26, 0x00, 0x00, 0x00, + 0x19, 0x56, 0xe4, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_13[78] = { + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x58, 0xa2, 0x00, 0x00, 0x00, + 0x0c, 0xa4, 0x30, 0x00, 0x00, 0x00, + 0xa1, 0x22, 0x46, 0x00, 0x00, 0x00, + 0x12, 0xa1, 0x1c, 0x00, 0x00, 0x00, + 0x8a, 0x45, 0xc0, 0x00, 0x00, 0x00, + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x12, 0x00, 0x00, 0x00, + 0xa4, 0x20, 0x4a, 0x00, 0x00, 0x00, + 0x50, 0xa0, 0xd4, 0x00, 0x00, 0x00, + 0x84, 0xc5, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x71, 0x0c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_14[84] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x12, 0x00, 0x00, 0x00, + 0xa4, 0x20, 0x4a, 0x00, 0x00, 0x00, + 0x50, 0xa0, 0xd4, 0x00, 0x00, 0x00, + 0x84, 0xc5, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x71, 0x0c, 0x00, 0x00, 0x00, + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x58, 0xa2, 0x00, 0x00, 0x00, + 0x0c, 0xa4, 0x30, 0x00, 0x00, 0x00, + 0xa1, 0x22, 0x46, 0x00, 0x00, 0x00, + 0x12, 0xa1, 0x1c, 0x00, 0x00, 0x00, + 0x8a, 0x45, 0xc0, 0x00, 0x00, 0x00, + 0x9c, 0x3f, 0xb2, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_15[90] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x12, 0x00, 0x00, 0x00, + 0xa4, 0x20, 0x4a, 0x00, 0x00, 0x00, + 0x50, 0xa0, 0xd4, 0x00, 0x00, 0x00, + 0x84, 0xc5, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x71, 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x84, 0x0c, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x88, 0x48, 0x00, 0x00, 0x00, + 0x05, 0x40, 0x32, 0x00, 0x00, 0x00, + 0x43, 0x02, 0x82, 0x00, 0x00, 0x00, + 0x1a, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x60, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x38, 0xa0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_16[96] = { + 0x0c, 0x84, 0x0c, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x88, 0x48, 0x00, 0x00, 0x00, + 0x05, 0x40, 0x32, 0x00, 0x00, 0x00, + 0x43, 0x02, 0x82, 0x00, 0x00, 0x00, + 0x1a, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x60, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x38, 0xa0, 0x00, 0x00, 0x00, + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x12, 0x00, 0x00, 0x00, + 0xa4, 0x20, 0x4a, 0x00, 0x00, 0x00, + 0x50, 0xa0, 0xd4, 0x00, 0x00, 0x00, + 0x84, 0xc5, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x71, 0x0c, 0x00, 0x00, 0x00, + 0xfa, 0xd9, 0xf4, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_17[102] = { + 0x0c, 0x84, 0x0c, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x88, 0x48, 0x00, 0x00, 0x00, + 0x05, 0x40, 0x32, 0x00, 0x00, 0x00, + 0x43, 0x02, 0x82, 0x00, 0x00, 0x00, + 0x1a, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x60, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x38, 0xa0, 0x00, 0x00, 0x00, + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x62, 0x7c, 0x84, 0x00, 0x00, 0x00, + 0x8c, 0x04, 0x88, 0x00, 0x00, 0x00, + 0x01, 0x74, 0x22, 0x00, 0x00, 0x00, + 0x07, 0x83, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x80, 0x72, 0x00, 0x00, 0x00, + 0x18, 0xb1, 0x42, 0x00, 0x00, 0x00, + 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x1c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_18[108] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x62, 0x7c, 0x84, 0x00, 0x00, 0x00, + 0x8c, 0x04, 0x88, 0x00, 0x00, 0x00, + 0x01, 0x74, 0x22, 0x00, 0x00, 0x00, + 0x07, 0x83, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x80, 0x72, 0x00, 0x00, 0x00, + 0x18, 0xb1, 0x42, 0x00, 0x00, 0x00, + 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x0c, 0x84, 0x0c, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x88, 0x48, 0x00, 0x00, 0x00, + 0x05, 0x40, 0x32, 0x00, 0x00, 0x00, + 0x43, 0x02, 0x82, 0x00, 0x00, 0x00, + 0x1a, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x60, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x38, 0xa0, 0x00, 0x00, 0x00, + 0x82, 0x32, 0x56, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_19[114] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x62, 0x7c, 0x84, 0x00, 0x00, 0x00, + 0x8c, 0x04, 0x88, 0x00, 0x00, 0x00, + 0x01, 0x74, 0x22, 0x00, 0x00, 0x00, + 0x07, 0x83, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x80, 0x72, 0x00, 0x00, 0x00, + 0x18, 0xb1, 0x42, 0x00, 0x00, 0x00, + 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x48, 0xa2, 0x00, 0x00, 0x00, + 0xa9, 0x10, 0x1a, 0x00, 0x00, 0x00, + 0x04, 0xc4, 0x84, 0x00, 0x00, 0x00, + 0xd0, 0x01, 0x44, 0x00, 0x00, 0x00, + 0x82, 0x40, 0x1c, 0x00, 0x00, 0x00, + 0x21, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x22, 0x00, 0x00, 0x00, + 0x4a, 0x0a, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0xb4, 0x50, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_2[12] = { + 0xec, 0xdd, 0x98, 0x00, 0x00, 0x00, + 0x9b, 0xb2, 0x76, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_20[120] = { + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x48, 0xa2, 0x00, 0x00, 0x00, + 0xa9, 0x10, 0x1a, 0x00, 0x00, 0x00, + 0x04, 0xc4, 0x84, 0x00, 0x00, 0x00, + 0xd0, 0x01, 0x44, 0x00, 0x00, 0x00, + 0x82, 0x40, 0x1c, 0x00, 0x00, 0x00, + 0x21, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x22, 0x00, 0x00, 0x00, + 0x4a, 0x0a, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0xb4, 0x50, 0x00, 0x00, 0x00, + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x62, 0x7c, 0x84, 0x00, 0x00, 0x00, + 0x8c, 0x04, 0x88, 0x00, 0x00, 0x00, + 0x01, 0x74, 0x22, 0x00, 0x00, 0x00, + 0x07, 0x83, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x80, 0x72, 0x00, 0x00, 0x00, + 0x18, 0xb1, 0x42, 0x00, 0x00, 0x00, + 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0xdb, 0x4a, 0x7a, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_21[126] = { + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x48, 0xa2, 0x00, 0x00, 0x00, + 0xa9, 0x10, 0x1a, 0x00, 0x00, 0x00, + 0x04, 0xc4, 0x84, 0x00, 0x00, 0x00, + 0xd0, 0x01, 0x44, 0x00, 0x00, 0x00, + 0x82, 0x40, 0x1c, 0x00, 0x00, 0x00, + 0x21, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x22, 0x00, 0x00, 0x00, + 0x4a, 0x0a, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0xb4, 0x50, 0x00, 0x00, 0x00, + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x99, 0x02, 0x12, 0x00, 0x00, 0x00, + 0x05, 0x80, 0x0e, 0x00, 0x00, 0x00, + 0x80, 0xa1, 0x82, 0x00, 0x00, 0x00, + 0x84, 0x48, 0x18, 0x00, 0x00, 0x00, + 0x40, 0x6d, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0x68, 0x04, 0x90, 0x00, 0x00, 0x00, + 0x10, 0x31, 0x20, 0x00, 0x00, 0x00, + 0x30, 0x58, 0x04, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_22[132] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x99, 0x02, 0x12, 0x00, 0x00, 0x00, + 0x05, 0x80, 0x0e, 0x00, 0x00, 0x00, + 0x80, 0xa1, 0x82, 0x00, 0x00, 0x00, + 0x84, 0x48, 0x18, 0x00, 0x00, 0x00, + 0x40, 0x6d, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0x68, 0x04, 0x90, 0x00, 0x00, 0x00, + 0x10, 0x31, 0x20, 0x00, 0x00, 0x00, + 0x30, 0x58, 0x04, 0x00, 0x00, 0x00, + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x48, 0xa2, 0x00, 0x00, 0x00, + 0xa9, 0x10, 0x1a, 0x00, 0x00, 0x00, + 0x04, 0xc4, 0x84, 0x00, 0x00, 0x00, + 0xd0, 0x01, 0x44, 0x00, 0x00, 0x00, + 0x82, 0x40, 0x1c, 0x00, 0x00, 0x00, + 0x21, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x21, 0x22, 0x00, 0x00, 0x00, + 0x4a, 0x0a, 0xc0, 0x00, 0x00, 0x00, + 0x12, 0xb4, 0x50, 0x00, 0x00, 0x00, + 0xea, 0x8d, 0x1a, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_23[138] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x99, 0x02, 0x12, 0x00, 0x00, 0x00, + 0x05, 0x80, 0x0e, 0x00, 0x00, 0x00, + 0x80, 0xa1, 0x82, 0x00, 0x00, 0x00, + 0x84, 0x48, 0x18, 0x00, 0x00, 0x00, + 0x40, 0x6d, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x90, 0xc0, 0x00, 0x00, 0x00, + 0x68, 0x04, 0x90, 0x00, 0x00, 0x00, + 0x10, 0x31, 0x20, 0x00, 0x00, 0x00, + 0x30, 0x58, 0x04, 0x00, 0x00, 0x00, + 0x46, 0x42, 0x0c, 0x00, 0x00, 0x00, + 0x33, 0x20, 0x46, 0x00, 0x00, 0x00, + 0x99, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x05, 0x84, 0x30, 0x00, 0x00, 0x00, + 0x80, 0xb0, 0x22, 0x00, 0x00, 0x00, + 0x84, 0x42, 0x90, 0x00, 0x00, 0x00, + 0x40, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x81, 0x12, 0x00, 0x00, 0x00, + 0x68, 0x0c, 0x40, 0x00, 0x00, 0x00, + 0x10, 0x24, 0x84, 0x00, 0x00, 0x00, + 0x30, 0x51, 0x40, 0x00, 0x00, 0x00, + 0x5f, 0x50, 0x88, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_3[18] = { + 0xca, 0xd3, 0x64, 0x00, 0x00, 0x00, + 0xf1, 0x49, 0x3a, 0x00, 0x00, 0x00, + 0x76, 0x27, 0xd0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_4[24] = { + 0xc4, 0xd1, 0x64, 0x00, 0x00, 0x00, + 0x31, 0x62, 0x96, 0x00, 0x00, 0x00, + 0x4b, 0x24, 0x5a, 0x00, 0x00, 0x00, + 0x2c, 0xa8, 0xaa, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_5[30] = { + 0xc6, 0xca, 0x6c, 0x00, 0x00, 0x00, + 0x63, 0x6c, 0x96, 0x00, 0x00, 0x00, + 0x1d, 0xa1, 0xdc, 0x00, 0x00, 0x00, + 0xad, 0x55, 0x38, 0x00, 0x00, 0x00, + 0xb2, 0xb7, 0x06, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_6[36] = { + 0x64, 0x4a, 0x28, 0x00, 0x00, 0x00, + 0x51, 0x58, 0xa2, 0x00, 0x00, 0x00, + 0x0c, 0xa4, 0x30, 0x00, 0x00, 0x00, + 0xa1, 0x22, 0x46, 0x00, 0x00, 0x00, + 0x12, 0xa1, 0x1c, 0x00, 0x00, 0x00, + 0x8a, 0x45, 0xc0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_7[42] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x33, 0x24, 0x26, 0x00, 0x00, 0x00, + 0x91, 0x92, 0x12, 0x00, 0x00, 0x00, + 0xa4, 0x20, 0x4a, 0x00, 0x00, 0x00, + 0x50, 0xa0, 0xd4, 0x00, 0x00, 0x00, + 0x84, 0xc5, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x71, 0x0c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_8[48] = { + 0x0c, 0x84, 0x0c, 0x00, 0x00, 0x00, + 0x80, 0x70, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x88, 0x48, 0x00, 0x00, 0x00, + 0x05, 0x40, 0x32, 0x00, 0x00, 0x00, + 0x43, 0x02, 0x82, 0x00, 0x00, 0x00, + 0x1a, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x60, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x38, 0xa0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom23_9[54] = { + 0x46, 0x4a, 0x6c, 0x00, 0x00, 0x00, + 0x62, 0x7c, 0x84, 0x00, 0x00, 0x00, + 0x8c, 0x04, 0x88, 0x00, 0x00, 0x00, + 0x01, 0x74, 0x22, 0x00, 0x00, 0x00, + 0x07, 0x83, 0x06, 0x00, 0x00, 0x00, + 0xa0, 0x80, 0x72, 0x00, 0x00, 0x00, + 0x18, 0xb1, 0x42, 0x00, 0x00, 0x00, + 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x1c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_1[6] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_10[60] = { + 0x11, 0x45, 0x14, 0x00, 0x00, 0x00, + 0x45, 0x34, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x05, 0x00, 0x00, 0x00, + 0x10, 0x83, 0x09, 0x00, 0x00, 0x00, + 0x4a, 0x14, 0xa1, 0x00, 0x00, 0x00, + 0x40, 0xa4, 0x0a, 0x00, 0x00, 0x00, + 0xa0, 0x6a, 0x02, 0x00, 0x00, 0x00, + 0x88, 0x80, 0x8c, 0x00, 0x00, 0x00, + 0x86, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x54, 0x0d, 0x40, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_11[66] = { + 0x53, 0x65, 0x34, 0x00, 0x00, 0x00, + 0xa0, 0x32, 0x11, 0x00, 0x00, 0x00, + 0x15, 0x11, 0x41, 0x00, 0x00, 0x00, + 0x03, 0x50, 0x15, 0x00, 0x00, 0x00, + 0x8c, 0x88, 0xc8, 0x00, 0x00, 0x00, + 0x28, 0x82, 0x88, 0x00, 0x00, 0x00, + 0x08, 0x48, 0x84, 0x00, 0x00, 0x00, + 0x99, 0x01, 0x90, 0x00, 0x00, 0x00, + 0x22, 0x92, 0x29, 0x00, 0x00, 0x00, + 0x46, 0x04, 0x60, 0x00, 0x00, 0x00, + 0x8c, 0x2c, 0x02, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_12[72] = { + 0x10, 0x61, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x30, 0x23, 0x00, 0x00, 0x00, + 0x40, 0x54, 0x05, 0x00, 0x00, 0x00, + 0x21, 0x82, 0x18, 0x00, 0x00, 0x00, + 0x81, 0x18, 0x11, 0x00, 0x00, 0x00, + 0x14, 0x81, 0x48, 0x00, 0x00, 0x00, + 0x98, 0x09, 0x80, 0x00, 0x00, 0x00, + 0x08, 0x90, 0x89, 0x00, 0x00, 0x00, + 0x62, 0x06, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x8a, 0x08, 0xa0, 0x00, 0x00, 0x00, + 0x84, 0x48, 0x44, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_13[78] = { + 0x51, 0x45, 0x14, 0x00, 0x00, 0x00, + 0xc5, 0x1c, 0x51, 0x00, 0x00, 0x00, + 0x21, 0x82, 0x18, 0x00, 0x00, 0x00, + 0x12, 0x31, 0x23, 0x00, 0x00, 0x00, + 0x08, 0xe0, 0x8e, 0x00, 0x00, 0x00, + 0x2e, 0x02, 0xe0, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x90, 0x99, 0x09, 0x00, 0x00, 0x00, + 0x02, 0x50, 0x25, 0x00, 0x00, 0x00, + 0x06, 0xa0, 0x6a, 0x00, 0x00, 0x00, + 0x2c, 0x02, 0xc0, 0x00, 0x00, 0x00, + 0x88, 0x68, 0x86, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_14[84] = { + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x90, 0x99, 0x09, 0x00, 0x00, 0x00, + 0x02, 0x50, 0x25, 0x00, 0x00, 0x00, + 0x06, 0xa0, 0x6a, 0x00, 0x00, 0x00, + 0x2c, 0x02, 0xc0, 0x00, 0x00, 0x00, + 0x88, 0x68, 0x86, 0x00, 0x00, 0x00, + 0x51, 0x45, 0x14, 0x00, 0x00, 0x00, + 0xc5, 0x1c, 0x51, 0x00, 0x00, 0x00, + 0x21, 0x82, 0x18, 0x00, 0x00, 0x00, + 0x12, 0x31, 0x23, 0x00, 0x00, 0x00, + 0x08, 0xe0, 0x8e, 0x00, 0x00, 0x00, + 0x2e, 0x02, 0xe0, 0x00, 0x00, 0x00, + 0xf2, 0xd6, 0x8e, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_15[90] = { + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x90, 0x99, 0x09, 0x00, 0x00, 0x00, + 0x02, 0x50, 0x25, 0x00, 0x00, 0x00, + 0x06, 0xa0, 0x6a, 0x00, 0x00, 0x00, + 0x2c, 0x02, 0xc0, 0x00, 0x00, 0x00, + 0x88, 0x68, 0x86, 0x00, 0x00, 0x00, + 0x20, 0x62, 0x06, 0x00, 0x00, 0x00, + 0x80, 0x38, 0x03, 0x00, 0x00, 0x00, + 0x42, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x01, 0x90, 0x19, 0x00, 0x00, 0x00, + 0x14, 0x11, 0x41, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0xa8, 0x00, 0x00, 0x00, + 0x38, 0x03, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0c, 0x50, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_16[96] = { + 0x20, 0x62, 0x06, 0x00, 0x00, 0x00, + 0x80, 0x38, 0x03, 0x00, 0x00, 0x00, + 0x42, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x01, 0x90, 0x19, 0x00, 0x00, 0x00, + 0x14, 0x11, 0x41, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0xa8, 0x00, 0x00, 0x00, + 0x38, 0x03, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0c, 0x50, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x90, 0x99, 0x09, 0x00, 0x00, 0x00, + 0x02, 0x50, 0x25, 0x00, 0x00, 0x00, + 0x06, 0xa0, 0x6a, 0x00, 0x00, 0x00, + 0x2c, 0x02, 0xc0, 0x00, 0x00, 0x00, + 0x88, 0x68, 0x86, 0x00, 0x00, 0x00, + 0xff, 0x6e, 0x0a, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_17[102] = { + 0x20, 0x62, 0x06, 0x00, 0x00, 0x00, + 0x80, 0x38, 0x03, 0x00, 0x00, 0x00, + 0x42, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x01, 0x90, 0x19, 0x00, 0x00, 0x00, + 0x14, 0x11, 0x41, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0xa8, 0x00, 0x00, 0x00, + 0x38, 0x03, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0c, 0x50, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0xe4, 0x2e, 0x42, 0x00, 0x00, 0x00, + 0x24, 0x42, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x1a, 0x11, 0x00, 0x00, 0x00, + 0x18, 0x31, 0x83, 0x00, 0x00, 0x00, + 0x03, 0x90, 0x39, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0xa1, 0x00, 0x00, 0x00, + 0x04, 0x90, 0x49, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_18[108] = { + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0xe4, 0x2e, 0x42, 0x00, 0x00, 0x00, + 0x24, 0x42, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x1a, 0x11, 0x00, 0x00, 0x00, + 0x18, 0x31, 0x83, 0x00, 0x00, 0x00, + 0x03, 0x90, 0x39, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0xa1, 0x00, 0x00, 0x00, + 0x04, 0x90, 0x49, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x62, 0x06, 0x00, 0x00, 0x00, + 0x80, 0x38, 0x03, 0x00, 0x00, 0x00, + 0x42, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x01, 0x90, 0x19, 0x00, 0x00, 0x00, + 0x14, 0x11, 0x41, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0xa8, 0x00, 0x00, 0x00, + 0x38, 0x03, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0c, 0x50, 0x00, 0x00, 0x00, + 0x34, 0x50, 0xae, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_19[114] = { + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0xe4, 0x2e, 0x42, 0x00, 0x00, 0x00, + 0x24, 0x42, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x1a, 0x11, 0x00, 0x00, 0x00, + 0x18, 0x31, 0x83, 0x00, 0x00, 0x00, + 0x03, 0x90, 0x39, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0xa1, 0x00, 0x00, 0x00, + 0x04, 0x90, 0x49, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, + 0x51, 0x45, 0x14, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x51, 0x00, 0x00, 0x00, + 0x80, 0xd8, 0x0d, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x0a, 0x20, 0xa2, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, + 0xb8, 0x0b, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x10, 0x91, 0x00, 0x00, 0x00, + 0x56, 0x05, 0x60, 0x00, 0x00, 0x00, + 0xa2, 0x8a, 0x28, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_2[12] = { + 0xec, 0xce, 0xcc, 0x00, 0x00, 0x00, + 0x93, 0xb9, 0x3b, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_20[120] = { + 0x51, 0x45, 0x14, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x51, 0x00, 0x00, 0x00, + 0x80, 0xd8, 0x0d, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x0a, 0x20, 0xa2, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, + 0xb8, 0x0b, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x10, 0x91, 0x00, 0x00, 0x00, + 0x56, 0x05, 0x60, 0x00, 0x00, 0x00, + 0xa2, 0x8a, 0x28, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0xe4, 0x2e, 0x42, 0x00, 0x00, 0x00, + 0x24, 0x42, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x1a, 0x11, 0x00, 0x00, 0x00, + 0x18, 0x31, 0x83, 0x00, 0x00, 0x00, + 0x03, 0x90, 0x39, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0xa1, 0x00, 0x00, 0x00, + 0x04, 0x90, 0x49, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, + 0x98, 0xa2, 0x95, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_21[126] = { + 0x51, 0x45, 0x14, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x51, 0x00, 0x00, 0x00, + 0x80, 0xd8, 0x0d, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x0a, 0x20, 0xa2, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, + 0xb8, 0x0b, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x10, 0x91, 0x00, 0x00, 0x00, + 0x56, 0x05, 0x60, 0x00, 0x00, 0x00, + 0xa2, 0x8a, 0x28, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x07, 0x00, 0x00, 0x00, + 0x0c, 0x10, 0xc1, 0x00, 0x00, 0x00, + 0x40, 0xc4, 0x0c, 0x00, 0x00, 0x00, + 0x6a, 0x06, 0xa0, 0x00, 0x00, 0x00, + 0x86, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x24, 0x82, 0x48, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x90, 0x00, 0x00, 0x00, + 0xc0, 0x2c, 0x02, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_22[132] = { + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x07, 0x00, 0x00, 0x00, + 0x0c, 0x10, 0xc1, 0x00, 0x00, 0x00, + 0x40, 0xc4, 0x0c, 0x00, 0x00, 0x00, + 0x6a, 0x06, 0xa0, 0x00, 0x00, 0x00, + 0x86, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x24, 0x82, 0x48, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x90, 0x00, 0x00, 0x00, + 0xc0, 0x2c, 0x02, 0x00, 0x00, 0x00, + 0x51, 0x45, 0x14, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x51, 0x00, 0x00, 0x00, + 0x80, 0xd8, 0x0d, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x0a, 0x20, 0xa2, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, + 0xb8, 0x0b, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x10, 0x91, 0x00, 0x00, 0x00, + 0x56, 0x05, 0x60, 0x00, 0x00, 0x00, + 0xa2, 0x8a, 0x28, 0x00, 0x00, 0x00, + 0x1a, 0xaa, 0xee, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_23[138] = { + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x07, 0x00, 0x00, 0x00, + 0x0c, 0x10, 0xc1, 0x00, 0x00, 0x00, + 0x40, 0xc4, 0x0c, 0x00, 0x00, 0x00, + 0x6a, 0x06, 0xa0, 0x00, 0x00, 0x00, + 0x86, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x24, 0x82, 0x48, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x90, 0x00, 0x00, 0x00, + 0xc0, 0x2c, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x61, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x30, 0x23, 0x00, 0x00, 0x00, + 0x40, 0x54, 0x05, 0x00, 0x00, 0x00, + 0x21, 0x82, 0x18, 0x00, 0x00, 0x00, + 0x81, 0x18, 0x11, 0x00, 0x00, 0x00, + 0x14, 0x81, 0x48, 0x00, 0x00, 0x00, + 0x98, 0x09, 0x80, 0x00, 0x00, 0x00, + 0x08, 0x90, 0x89, 0x00, 0x00, 0x00, + 0x62, 0x06, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x8a, 0x08, 0xa0, 0x00, 0x00, 0x00, + 0x84, 0x48, 0x44, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_24[144] = { + 0x10, 0x61, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x30, 0x23, 0x00, 0x00, 0x00, + 0x40, 0x54, 0x05, 0x00, 0x00, 0x00, + 0x21, 0x82, 0x18, 0x00, 0x00, 0x00, + 0x81, 0x18, 0x11, 0x00, 0x00, 0x00, + 0x14, 0x81, 0x48, 0x00, 0x00, 0x00, + 0x98, 0x09, 0x80, 0x00, 0x00, 0x00, + 0x08, 0x90, 0x89, 0x00, 0x00, 0x00, + 0x62, 0x06, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x42, 0x00, 0x00, 0x00, + 0x8a, 0x08, 0xa0, 0x00, 0x00, 0x00, + 0x84, 0x48, 0x44, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x13, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x07, 0x00, 0x00, 0x00, + 0x0c, 0x10, 0xc1, 0x00, 0x00, 0x00, + 0x40, 0xc4, 0x0c, 0x00, 0x00, 0x00, + 0x6a, 0x06, 0xa0, 0x00, 0x00, 0x00, + 0x86, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x24, 0x82, 0x48, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x90, 0x00, 0x00, 0x00, + 0xc0, 0x2c, 0x02, 0x00, 0x00, 0x00, + 0x88, 0x32, 0x59, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_3[18] = { + 0x9b, 0x29, 0xb2, 0x00, 0x00, 0x00, + 0x49, 0xd4, 0x9d, 0x00, 0x00, 0x00, + 0x3e, 0x83, 0xe8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_4[24] = { + 0x8b, 0x28, 0xb2, 0x00, 0x00, 0x00, + 0x14, 0xb1, 0x4b, 0x00, 0x00, 0x00, + 0x22, 0xd2, 0x2d, 0x00, 0x00, 0x00, + 0x45, 0x54, 0x55, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_5[30] = { + 0x53, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x64, 0xb6, 0x4b, 0x00, 0x00, 0x00, + 0x0e, 0xe0, 0xee, 0x00, 0x00, 0x00, + 0xa9, 0xca, 0x9c, 0x00, 0x00, 0x00, + 0xb8, 0x3b, 0x83, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_6[36] = { + 0xd1, 0x4d, 0x14, 0x00, 0x00, 0x00, + 0x45, 0x34, 0x53, 0x00, 0x00, 0x00, + 0x22, 0xd2, 0x2d, 0x00, 0x00, 0x00, + 0x16, 0xc1, 0x6c, 0x00, 0x00, 0x00, + 0x0b, 0xa0, 0xba, 0x00, 0x00, 0x00, + 0xe8, 0x8e, 0x88, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_7[42] = { + 0xd3, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x25, 0x32, 0x53, 0x00, 0x00, 0x00, + 0x30, 0xd3, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x48, 0x6c, 0x00, 0x00, 0x00, + 0xc0, 0xb8, 0x1b, 0x00, 0x00, 0x00, + 0x2a, 0xa2, 0xaa, 0x00, 0x00, 0x00, + 0xa8, 0x4e, 0x84, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_8[48] = { + 0x81, 0x60, 0x16, 0x00, 0x00, 0x00, + 0x40, 0x3c, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x09, 0x00, 0x00, 0x00, + 0x06, 0x50, 0x65, 0x00, 0x00, 0x00, + 0x20, 0x4a, 0x84, 0x00, 0x00, 0x00, + 0x8a, 0xa0, 0xaa, 0x00, 0x00, 0x00, + 0x33, 0x03, 0x30, 0x00, 0x00, 0x00, + 0x4c, 0x84, 0xc8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom24_9[54] = { + 0xd3, 0x65, 0x36, 0x00, 0x00, 0x00, + 0x64, 0x26, 0x42, 0x00, 0x00, 0x00, + 0x18, 0x41, 0xc4, 0x00, 0x00, 0x00, + 0xa0, 0x4a, 0x04, 0x00, 0x00, 0x00, + 0x81, 0x38, 0x13, 0x00, 0x00, 0x00, + 0x22, 0xa2, 0x2a, 0x00, 0x00, 0x00, + 0x08, 0x70, 0x87, 0x00, 0x00, 0x00, + 0x04, 0x90, 0x49, 0x00, 0x00, 0x00, + 0x01, 0xc0, 0x1c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_1[6] = { + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_10[60] = { + 0x51, 0x4d, 0x10, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x45, 0x00, 0x00, 0x00, + 0x80, 0xd1, 0x09, 0x80, 0x00, 0x00, + 0x24, 0x2a, 0x05, 0x00, 0x00, 0x00, + 0x0a, 0x24, 0xa0, 0x80, 0x00, 0x00, + 0x00, 0xe4, 0x03, 0x00, 0x00, 0x00, + 0xb8, 0x08, 0x02, 0x80, 0x00, 0x00, + 0x09, 0x10, 0xc9, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x58, 0x80, 0x00, 0x00, + 0xa2, 0x86, 0x22, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_11[66] = { + 0x53, 0x65, 0x12, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x21, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x72, 0x50, 0x00, 0x00, 0x00, + 0x0c, 0x11, 0x81, 0x80, 0x00, 0x00, + 0x40, 0xc0, 0xa2, 0x00, 0x00, 0x00, + 0x6a, 0x08, 0x88, 0x80, 0x00, 0x00, + 0x86, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x24, 0x8e, 0x02, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x44, 0x00, 0x00, 0x00, + 0xc0, 0x24, 0x41, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_12[72] = { + 0x10, 0x62, 0x82, 0x80, 0x00, 0x00, + 0x02, 0x38, 0x45, 0x00, 0x00, 0x00, + 0x40, 0x56, 0x04, 0x00, 0x00, 0x00, + 0x21, 0x80, 0x54, 0x80, 0x00, 0x00, + 0x81, 0x10, 0x29, 0x80, 0x00, 0x00, + 0x14, 0x80, 0x13, 0x00, 0x00, 0x00, + 0x98, 0x04, 0x81, 0x00, 0x00, 0x00, + 0x08, 0x92, 0x48, 0x00, 0x00, 0x00, + 0x62, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x24, 0x28, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x01, 0x18, 0x00, 0x00, 0x00, + 0x84, 0x45, 0x22, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_13[78] = { + 0x51, 0x4d, 0x12, 0x00, 0x00, 0x00, + 0xc5, 0x14, 0x6d, 0x00, 0x00, 0x00, + 0x21, 0x81, 0x54, 0x80, 0x00, 0x00, + 0x12, 0x32, 0x17, 0x00, 0x00, 0x00, + 0x08, 0xe2, 0x8c, 0x80, 0x00, 0x00, + 0x2e, 0x0a, 0xa2, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x65, 0x00, 0x00, 0x00, + 0x90, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x02, 0x52, 0xb0, 0x80, 0x00, 0x00, + 0x06, 0xa1, 0x4c, 0x80, 0x00, 0x00, + 0x2c, 0x0c, 0x88, 0x80, 0x00, 0x00, + 0x88, 0x68, 0x4b, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_14[84] = { + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x65, 0x00, 0x00, 0x00, + 0x90, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x02, 0x52, 0xb0, 0x80, 0x00, 0x00, + 0x06, 0xa1, 0x4c, 0x80, 0x00, 0x00, + 0x2c, 0x0c, 0x88, 0x80, 0x00, 0x00, + 0x88, 0x68, 0x4b, 0x00, 0x00, 0x00, + 0x51, 0x4d, 0x12, 0x00, 0x00, 0x00, + 0xc5, 0x14, 0x6d, 0x00, 0x00, 0x00, + 0x21, 0x81, 0x54, 0x80, 0x00, 0x00, + 0x12, 0x32, 0x17, 0x00, 0x00, 0x00, + 0x08, 0xe2, 0x8c, 0x80, 0x00, 0x00, + 0x2e, 0x0a, 0xa2, 0x00, 0x00, 0x00, + 0x73, 0x76, 0x61, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_15[90] = { + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x65, 0x00, 0x00, 0x00, + 0x90, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x02, 0x52, 0xb0, 0x80, 0x00, 0x00, + 0x06, 0xa1, 0x4c, 0x80, 0x00, 0x00, + 0x2c, 0x0c, 0x88, 0x80, 0x00, 0x00, + 0x88, 0x68, 0x4b, 0x00, 0x00, 0x00, + 0x20, 0x68, 0x0a, 0x80, 0x00, 0x00, + 0x80, 0x33, 0x09, 0x00, 0x00, 0x00, + 0x42, 0x41, 0x60, 0x80, 0x00, 0x00, + 0x01, 0x90, 0x33, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x46, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0x81, 0x80, 0x00, 0x00, + 0x38, 0x0d, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0a, 0x14, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_16[96] = { + 0x20, 0x68, 0x0a, 0x80, 0x00, 0x00, + 0x80, 0x33, 0x09, 0x00, 0x00, 0x00, + 0x42, 0x41, 0x60, 0x80, 0x00, 0x00, + 0x01, 0x90, 0x33, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x46, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0x81, 0x80, 0x00, 0x00, + 0x38, 0x0d, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0a, 0x14, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x65, 0x00, 0x00, 0x00, + 0x90, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x02, 0x52, 0xb0, 0x80, 0x00, 0x00, + 0x06, 0xa1, 0x4c, 0x80, 0x00, 0x00, + 0x2c, 0x0c, 0x88, 0x80, 0x00, 0x00, + 0x88, 0x68, 0x4b, 0x00, 0x00, 0x00, + 0x16, 0xe8, 0xdc, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_17[102] = { + 0x20, 0x68, 0x0a, 0x80, 0x00, 0x00, + 0x80, 0x33, 0x09, 0x00, 0x00, 0x00, + 0x42, 0x41, 0x60, 0x80, 0x00, 0x00, + 0x01, 0x90, 0x33, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x46, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0x81, 0x80, 0x00, 0x00, + 0x38, 0x0d, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0a, 0x14, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0xe4, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x24, 0x41, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x12, 0x14, 0x80, 0x00, 0x00, + 0x18, 0x30, 0x2c, 0x80, 0x00, 0x00, + 0x03, 0x99, 0x41, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0x0a, 0x80, 0x00, 0x00, + 0x04, 0x90, 0xa9, 0x00, 0x00, 0x00, + 0x00, 0xe4, 0x01, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_18[108] = { + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0xe4, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x24, 0x41, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x12, 0x14, 0x80, 0x00, 0x00, + 0x18, 0x30, 0x2c, 0x80, 0x00, 0x00, + 0x03, 0x99, 0x41, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0x0a, 0x80, 0x00, 0x00, + 0x04, 0x90, 0xa9, 0x00, 0x00, 0x00, + 0x00, 0xe4, 0x01, 0x80, 0x00, 0x00, + 0x20, 0x68, 0x0a, 0x80, 0x00, 0x00, + 0x80, 0x33, 0x09, 0x00, 0x00, 0x00, + 0x42, 0x41, 0x60, 0x80, 0x00, 0x00, + 0x01, 0x90, 0x33, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x46, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0x81, 0x80, 0x00, 0x00, + 0x38, 0x0d, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0a, 0x14, 0x00, 0x00, 0x00, + 0xce, 0x9b, 0xe1, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_19[114] = { + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0xe4, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x24, 0x41, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x12, 0x14, 0x80, 0x00, 0x00, + 0x18, 0x30, 0x2c, 0x80, 0x00, 0x00, + 0x03, 0x99, 0x41, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0x0a, 0x80, 0x00, 0x00, + 0x04, 0x90, 0xa9, 0x00, 0x00, 0x00, + 0x00, 0xe4, 0x01, 0x80, 0x00, 0x00, + 0x51, 0x4d, 0x10, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x45, 0x00, 0x00, 0x00, + 0x80, 0xd1, 0x09, 0x80, 0x00, 0x00, + 0x24, 0x2a, 0x05, 0x00, 0x00, 0x00, + 0x0a, 0x24, 0xa0, 0x80, 0x00, 0x00, + 0x00, 0xe4, 0x03, 0x00, 0x00, 0x00, + 0xb8, 0x08, 0x02, 0x80, 0x00, 0x00, + 0x09, 0x10, 0xc9, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x58, 0x80, 0x00, 0x00, + 0xa2, 0x86, 0x22, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_2[12] = { + 0xec, 0xce, 0xcc, 0x00, 0x00, 0x00, + 0x93, 0xb1, 0xb3, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_20[120] = { + 0x51, 0x4d, 0x10, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x45, 0x00, 0x00, 0x00, + 0x80, 0xd1, 0x09, 0x80, 0x00, 0x00, + 0x24, 0x2a, 0x05, 0x00, 0x00, 0x00, + 0x0a, 0x24, 0xa0, 0x80, 0x00, 0x00, + 0x00, 0xe4, 0x03, 0x00, 0x00, 0x00, + 0xb8, 0x08, 0x02, 0x80, 0x00, 0x00, + 0x09, 0x10, 0xc9, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x58, 0x80, 0x00, 0x00, + 0xa2, 0x86, 0x22, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0xe4, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x24, 0x41, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x12, 0x14, 0x80, 0x00, 0x00, + 0x18, 0x30, 0x2c, 0x80, 0x00, 0x00, + 0x03, 0x99, 0x41, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0x0a, 0x80, 0x00, 0x00, + 0x04, 0x90, 0xa9, 0x00, 0x00, 0x00, + 0x00, 0xe4, 0x01, 0x80, 0x00, 0x00, + 0x1b, 0x8a, 0xa0, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_21[126] = { + 0x51, 0x4d, 0x10, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x45, 0x00, 0x00, 0x00, + 0x80, 0xd1, 0x09, 0x80, 0x00, 0x00, + 0x24, 0x2a, 0x05, 0x00, 0x00, 0x00, + 0x0a, 0x24, 0xa0, 0x80, 0x00, 0x00, + 0x00, 0xe4, 0x03, 0x00, 0x00, 0x00, + 0xb8, 0x08, 0x02, 0x80, 0x00, 0x00, + 0x09, 0x10, 0xc9, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x58, 0x80, 0x00, 0x00, + 0xa2, 0x86, 0x22, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x12, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x21, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x72, 0x50, 0x00, 0x00, 0x00, + 0x0c, 0x11, 0x81, 0x80, 0x00, 0x00, + 0x40, 0xc0, 0xa2, 0x00, 0x00, 0x00, + 0x6a, 0x08, 0x88, 0x80, 0x00, 0x00, + 0x86, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x24, 0x8e, 0x02, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x44, 0x00, 0x00, 0x00, + 0xc0, 0x24, 0x41, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_22[132] = { + 0x53, 0x65, 0x12, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x21, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x72, 0x50, 0x00, 0x00, 0x00, + 0x0c, 0x11, 0x81, 0x80, 0x00, 0x00, + 0x40, 0xc0, 0xa2, 0x00, 0x00, 0x00, + 0x6a, 0x08, 0x88, 0x80, 0x00, 0x00, + 0x86, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x24, 0x8e, 0x02, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x44, 0x00, 0x00, 0x00, + 0xc0, 0x24, 0x41, 0x80, 0x00, 0x00, + 0x51, 0x4d, 0x10, 0x00, 0x00, 0x00, + 0x45, 0x14, 0x45, 0x00, 0x00, 0x00, + 0x80, 0xd1, 0x09, 0x80, 0x00, 0x00, + 0x24, 0x2a, 0x05, 0x00, 0x00, 0x00, + 0x0a, 0x24, 0xa0, 0x80, 0x00, 0x00, + 0x00, 0xe4, 0x03, 0x00, 0x00, 0x00, + 0xb8, 0x08, 0x02, 0x80, 0x00, 0x00, + 0x09, 0x10, 0xc9, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x58, 0x80, 0x00, 0x00, + 0xa2, 0x86, 0x22, 0x00, 0x00, 0x00, + 0x15, 0xa2, 0x99, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_23[138] = { + 0x53, 0x65, 0x12, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x21, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x72, 0x50, 0x00, 0x00, 0x00, + 0x0c, 0x11, 0x81, 0x80, 0x00, 0x00, + 0x40, 0xc0, 0xa2, 0x00, 0x00, 0x00, + 0x6a, 0x08, 0x88, 0x80, 0x00, 0x00, + 0x86, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x24, 0x8e, 0x02, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x44, 0x00, 0x00, 0x00, + 0xc0, 0x24, 0x41, 0x80, 0x00, 0x00, + 0x10, 0x62, 0x82, 0x80, 0x00, 0x00, + 0x02, 0x38, 0x45, 0x00, 0x00, 0x00, + 0x40, 0x56, 0x04, 0x00, 0x00, 0x00, + 0x21, 0x80, 0x54, 0x80, 0x00, 0x00, + 0x81, 0x10, 0x29, 0x80, 0x00, 0x00, + 0x14, 0x80, 0x13, 0x00, 0x00, 0x00, + 0x98, 0x04, 0x81, 0x00, 0x00, 0x00, + 0x08, 0x92, 0x48, 0x00, 0x00, 0x00, + 0x62, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x24, 0x28, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x01, 0x18, 0x00, 0x00, 0x00, + 0x84, 0x45, 0x22, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_24[144] = { + 0x10, 0x62, 0x82, 0x80, 0x00, 0x00, + 0x02, 0x38, 0x45, 0x00, 0x00, 0x00, + 0x40, 0x56, 0x04, 0x00, 0x00, 0x00, + 0x21, 0x80, 0x54, 0x80, 0x00, 0x00, + 0x81, 0x10, 0x29, 0x80, 0x00, 0x00, + 0x14, 0x80, 0x13, 0x00, 0x00, 0x00, + 0x98, 0x04, 0x81, 0x00, 0x00, 0x00, + 0x08, 0x92, 0x48, 0x00, 0x00, 0x00, + 0x62, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x24, 0x28, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x01, 0x18, 0x00, 0x00, 0x00, + 0x84, 0x45, 0x22, 0x00, 0x00, 0x00, + 0x53, 0x65, 0x12, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x21, 0x00, 0x00, 0x00, + 0x10, 0x91, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x72, 0x50, 0x00, 0x00, 0x00, + 0x0c, 0x11, 0x81, 0x80, 0x00, 0x00, + 0x40, 0xc0, 0xa2, 0x00, 0x00, 0x00, + 0x6a, 0x08, 0x88, 0x80, 0x00, 0x00, + 0x86, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x24, 0x8e, 0x02, 0x00, 0x00, 0x00, + 0x89, 0x08, 0x44, 0x00, 0x00, 0x00, + 0xc0, 0x24, 0x41, 0x80, 0x00, 0x00, + 0xf9, 0x0c, 0x14, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_25[150] = { + 0x10, 0x62, 0x82, 0x80, 0x00, 0x00, + 0x02, 0x38, 0x45, 0x00, 0x00, 0x00, + 0x40, 0x56, 0x04, 0x00, 0x00, 0x00, + 0x21, 0x80, 0x54, 0x80, 0x00, 0x00, + 0x81, 0x10, 0x29, 0x80, 0x00, 0x00, + 0x14, 0x80, 0x13, 0x00, 0x00, 0x00, + 0x98, 0x04, 0x81, 0x00, 0x00, 0x00, + 0x08, 0x92, 0x48, 0x00, 0x00, 0x00, + 0x62, 0x09, 0x40, 0x00, 0x00, 0x00, + 0x24, 0x28, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x01, 0x18, 0x00, 0x00, 0x00, + 0x84, 0x45, 0x22, 0x00, 0x00, 0x00, + 0x10, 0x65, 0x12, 0x00, 0x00, 0x00, + 0x02, 0x36, 0x64, 0x00, 0x00, 0x00, + 0x40, 0x50, 0x54, 0x80, 0x00, 0x00, + 0x21, 0x88, 0x12, 0x00, 0x00, 0x00, + 0x81, 0x19, 0x40, 0x00, 0x00, 0x00, + 0x14, 0x83, 0x08, 0x00, 0x00, 0x00, + 0x98, 0x02, 0x11, 0x00, 0x00, 0x00, + 0x08, 0x90, 0x3c, 0x00, 0x00, 0x00, + 0x62, 0x0e, 0x80, 0x00, 0x00, 0x00, + 0x24, 0x20, 0xa1, 0x00, 0x00, 0x00, + 0x8a, 0x08, 0x01, 0x80, 0x00, 0x00, + 0x84, 0x40, 0x49, 0x00, 0x00, 0x00, + 0x1c, 0x20, 0x8a, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_3[18] = { + 0x9b, 0x89, 0x9b, 0x00, 0x00, 0x00, + 0x4f, 0x14, 0x6d, 0x80, 0x00, 0x00, + 0x3c, 0x63, 0x72, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_4[24] = { + 0x8b, 0x24, 0x9b, 0x00, 0x00, 0x00, + 0x14, 0xb2, 0x6d, 0x00, 0x00, 0x00, + 0x22, 0xd8, 0x56, 0x80, 0x00, 0x00, + 0x45, 0x55, 0x25, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_5[30] = { + 0x53, 0x65, 0x13, 0x00, 0x00, 0x00, + 0x64, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x0c, 0xc0, 0xc6, 0x80, 0x00, 0x00, + 0x82, 0xaa, 0x1c, 0x00, 0x00, 0x00, + 0x09, 0x32, 0x29, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_6[36] = { + 0x51, 0x4d, 0x12, 0x00, 0x00, 0x00, + 0xc5, 0x14, 0x6d, 0x00, 0x00, 0x00, + 0x21, 0x81, 0x54, 0x80, 0x00, 0x00, + 0x12, 0x32, 0x17, 0x00, 0x00, 0x00, + 0x08, 0xe2, 0x8c, 0x80, 0x00, 0x00, + 0x2e, 0x0a, 0xa2, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_7[42] = { + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0x21, 0x32, 0x65, 0x00, 0x00, 0x00, + 0x90, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x02, 0x52, 0xb0, 0x80, 0x00, 0x00, + 0x06, 0xa1, 0x4c, 0x80, 0x00, 0x00, + 0x2c, 0x0c, 0x88, 0x80, 0x00, 0x00, + 0x88, 0x68, 0x4b, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_8[48] = { + 0x20, 0x68, 0x0a, 0x80, 0x00, 0x00, + 0x80, 0x33, 0x09, 0x00, 0x00, 0x00, + 0x42, 0x41, 0x60, 0x80, 0x00, 0x00, + 0x01, 0x90, 0x33, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x46, 0x00, 0x00, 0x00, + 0x0a, 0x80, 0x81, 0x80, 0x00, 0x00, + 0x38, 0x0d, 0x80, 0x00, 0x00, 0x00, + 0xc5, 0x0a, 0x14, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom25_9[54] = { + 0x53, 0x65, 0x92, 0x00, 0x00, 0x00, + 0xe4, 0x26, 0x64, 0x00, 0x00, 0x00, + 0x24, 0x41, 0x44, 0x00, 0x00, 0x00, + 0xa1, 0x12, 0x14, 0x80, 0x00, 0x00, + 0x18, 0x30, 0x2c, 0x80, 0x00, 0x00, + 0x03, 0x99, 0x41, 0x00, 0x00, 0x00, + 0x8a, 0x18, 0x0a, 0x80, 0x00, 0x00, + 0x04, 0x90, 0xa9, 0x00, 0x00, 0x00, + 0x00, 0xe4, 0x01, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_1[6] = { + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_10[60] = { + 0xd1, 0x06, 0x88, 0x00, 0x00, 0x00, + 0x44, 0x52, 0x22, 0x80, 0x00, 0x00, + 0x10, 0x98, 0x84, 0xc0, 0x00, 0x00, + 0xa0, 0x55, 0x02, 0x80, 0x00, 0x00, + 0x4a, 0x0a, 0x50, 0x40, 0x00, 0x00, + 0x40, 0x32, 0x01, 0x80, 0x00, 0x00, + 0x80, 0x2c, 0x01, 0x40, 0x00, 0x00, + 0x0c, 0x90, 0x64, 0x80, 0x00, 0x00, + 0x05, 0x88, 0x2c, 0x40, 0x00, 0x00, + 0x62, 0x23, 0x11, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_11[66] = { + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x22, 0x11, 0x10, 0x80, 0x00, 0x00, + 0x13, 0x40, 0x9a, 0x00, 0x00, 0x00, + 0x25, 0x01, 0x28, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xc0, 0xc0, 0x00, 0x00, + 0x0a, 0x20, 0x51, 0x00, 0x00, 0x00, + 0x88, 0x8c, 0x44, 0x40, 0x00, 0x00, + 0x06, 0x80, 0x34, 0x00, 0x00, 0x00, + 0xe0, 0x27, 0x01, 0x00, 0x00, 0x00, + 0x84, 0x44, 0x22, 0x00, 0x00, 0x00, + 0x44, 0x1a, 0x20, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_12[72] = { + 0x28, 0x29, 0x41, 0x40, 0x00, 0x00, + 0x84, 0x54, 0x22, 0x80, 0x00, 0x00, + 0x60, 0x43, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x02, 0x98, 0x14, 0xc0, 0x00, 0x00, + 0x01, 0x30, 0x09, 0x80, 0x00, 0x00, + 0x48, 0x12, 0x40, 0x80, 0x00, 0x00, + 0x24, 0x81, 0x24, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x04, 0x50, 0x00, 0x00, 0x00, + 0x11, 0x80, 0x8c, 0x00, 0x00, 0x00, + 0x52, 0x22, 0x91, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_13[78] = { + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x81, 0x24, 0x09, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x30, 0x81, 0x84, 0x00, 0x00, 0x00, + 0x21, 0x11, 0x08, 0x80, 0x00, 0x00, + 0x03, 0xc0, 0x1e, 0x00, 0x00, 0x00, + 0xe8, 0x07, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x10, 0x50, 0x80, 0x00, 0x00, + 0x80, 0x1c, 0x00, 0xc0, 0x00, 0x00, + 0x04, 0x90, 0x24, 0x80, 0x00, 0x00, + 0x08, 0xa8, 0x45, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_14[84] = { + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x26, 0x51, 0x32, 0x80, 0x00, 0x00, + 0xb1, 0x45, 0x8a, 0x00, 0x00, 0x00, + 0x2b, 0x09, 0x58, 0x40, 0x00, 0x00, + 0x14, 0xc8, 0xa6, 0x40, 0x00, 0x00, + 0xc8, 0x8e, 0x44, 0x40, 0x00, 0x00, + 0x84, 0xb4, 0x25, 0x80, 0x00, 0x00, + 0xd1, 0x26, 0x89, 0x00, 0x00, 0x00, + 0x46, 0xd2, 0x36, 0x80, 0x00, 0x00, + 0x15, 0x48, 0xaa, 0x40, 0x00, 0x00, + 0x21, 0x71, 0x0b, 0x80, 0x00, 0x00, + 0x28, 0xc9, 0x46, 0x40, 0x00, 0x00, + 0xaa, 0x25, 0x51, 0x00, 0x00, 0x00, + 0x5d, 0xa7, 0x78, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_15[90] = { + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x26, 0x51, 0x32, 0x80, 0x00, 0x00, + 0xb1, 0x45, 0x8a, 0x00, 0x00, 0x00, + 0x2b, 0x09, 0x58, 0x40, 0x00, 0x00, + 0x14, 0xc8, 0xa6, 0x40, 0x00, 0x00, + 0xc8, 0x8e, 0x44, 0x40, 0x00, 0x00, + 0x84, 0xb4, 0x25, 0x80, 0x00, 0x00, + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x30, 0x91, 0x84, 0x80, 0x00, 0x00, + 0x16, 0x08, 0xb0, 0x40, 0x00, 0x00, + 0x03, 0x30, 0x19, 0x80, 0x00, 0x00, + 0x44, 0x62, 0x23, 0x00, 0x00, 0x00, + 0x08, 0x18, 0x40, 0xc0, 0x00, 0x00, + 0xd8, 0x06, 0xc0, 0x00, 0x00, 0x00, + 0xa1, 0x45, 0x0a, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_16[96] = { + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x30, 0x91, 0x84, 0x80, 0x00, 0x00, + 0x16, 0x08, 0xb0, 0x40, 0x00, 0x00, + 0x03, 0x30, 0x19, 0x80, 0x00, 0x00, + 0x44, 0x62, 0x23, 0x00, 0x00, 0x00, + 0x08, 0x18, 0x40, 0xc0, 0x00, 0x00, + 0xd8, 0x06, 0xc0, 0x00, 0x00, 0x00, + 0xa1, 0x45, 0x0a, 0x00, 0x00, 0x00, + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x26, 0x51, 0x32, 0x80, 0x00, 0x00, + 0xb1, 0x45, 0x8a, 0x00, 0x00, 0x00, + 0x2b, 0x09, 0x58, 0x40, 0x00, 0x00, + 0x14, 0xc8, 0xa6, 0x40, 0x00, 0x00, + 0xc8, 0x8e, 0x44, 0x40, 0x00, 0x00, + 0x84, 0xb4, 0x25, 0x80, 0x00, 0x00, + 0x3c, 0xaf, 0x88, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_17[102] = { + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x30, 0x91, 0x84, 0x80, 0x00, 0x00, + 0x16, 0x08, 0xb0, 0x40, 0x00, 0x00, + 0x03, 0x30, 0x19, 0x80, 0x00, 0x00, + 0x44, 0x62, 0x23, 0x00, 0x00, 0x00, + 0x08, 0x18, 0x40, 0xc0, 0x00, 0x00, + 0xd8, 0x06, 0xc0, 0x00, 0x00, 0x00, + 0xa1, 0x45, 0x0a, 0x00, 0x00, 0x00, + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x14, 0x40, 0xa2, 0x00, 0x00, 0x00, + 0x21, 0x49, 0x0a, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x16, 0x40, 0x00, 0x00, + 0x94, 0x14, 0xa0, 0x80, 0x00, 0x00, + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x90, 0x54, 0x80, 0x00, 0x00, + 0x40, 0x1a, 0x00, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_18[108] = { + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x14, 0x40, 0xa2, 0x00, 0x00, 0x00, + 0x21, 0x49, 0x0a, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x16, 0x40, 0x00, 0x00, + 0x94, 0x14, 0xa0, 0x80, 0x00, 0x00, + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x90, 0x54, 0x80, 0x00, 0x00, + 0x40, 0x1a, 0x00, 0xc0, 0x00, 0x00, + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x30, 0x91, 0x84, 0x80, 0x00, 0x00, + 0x16, 0x08, 0xb0, 0x40, 0x00, 0x00, + 0x03, 0x30, 0x19, 0x80, 0x00, 0x00, + 0x44, 0x62, 0x23, 0x00, 0x00, 0x00, + 0x08, 0x18, 0x40, 0xc0, 0x00, 0x00, + 0xd8, 0x06, 0xc0, 0x00, 0x00, 0x00, + 0xa1, 0x45, 0x0a, 0x00, 0x00, 0x00, + 0xaa, 0x0c, 0x83, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_19[114] = { + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x14, 0x40, 0xa2, 0x00, 0x00, 0x00, + 0x21, 0x49, 0x0a, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x16, 0x40, 0x00, 0x00, + 0x94, 0x14, 0xa0, 0x80, 0x00, 0x00, + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x90, 0x54, 0x80, 0x00, 0x00, + 0x40, 0x1a, 0x00, 0xc0, 0x00, 0x00, + 0xd1, 0x06, 0x88, 0x00, 0x00, 0x00, + 0x44, 0x52, 0x22, 0x80, 0x00, 0x00, + 0x10, 0x98, 0x84, 0xc0, 0x00, 0x00, + 0xa0, 0x55, 0x02, 0x80, 0x00, 0x00, + 0x4a, 0x0a, 0x50, 0x40, 0x00, 0x00, + 0x40, 0x32, 0x01, 0x80, 0x00, 0x00, + 0x80, 0x2c, 0x01, 0x40, 0x00, 0x00, + 0x0c, 0x90, 0x64, 0x80, 0x00, 0x00, + 0x05, 0x88, 0x2c, 0x40, 0x00, 0x00, + 0x62, 0x23, 0x11, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_2[12] = { + 0xec, 0xc7, 0x66, 0x00, 0x00, 0x00, + 0x1b, 0x38, 0xd9, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_20[120] = { + 0xd1, 0x06, 0x88, 0x00, 0x00, 0x00, + 0x44, 0x52, 0x22, 0x80, 0x00, 0x00, + 0x10, 0x98, 0x84, 0xc0, 0x00, 0x00, + 0xa0, 0x55, 0x02, 0x80, 0x00, 0x00, + 0x4a, 0x0a, 0x50, 0x40, 0x00, 0x00, + 0x40, 0x32, 0x01, 0x80, 0x00, 0x00, + 0x80, 0x2c, 0x01, 0x40, 0x00, 0x00, + 0x0c, 0x90, 0x64, 0x80, 0x00, 0x00, + 0x05, 0x88, 0x2c, 0x40, 0x00, 0x00, + 0x62, 0x23, 0x11, 0x00, 0x00, 0x00, + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x14, 0x40, 0xa2, 0x00, 0x00, 0x00, + 0x21, 0x49, 0x0a, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x16, 0x40, 0x00, 0x00, + 0x94, 0x14, 0xa0, 0x80, 0x00, 0x00, + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x90, 0x54, 0x80, 0x00, 0x00, + 0x40, 0x1a, 0x00, 0xc0, 0x00, 0x00, + 0xf4, 0x08, 0xec, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_21[126] = { + 0xd1, 0x06, 0x88, 0x00, 0x00, 0x00, + 0x44, 0x52, 0x22, 0x80, 0x00, 0x00, + 0x10, 0x98, 0x84, 0xc0, 0x00, 0x00, + 0xa0, 0x55, 0x02, 0x80, 0x00, 0x00, + 0x4a, 0x0a, 0x50, 0x40, 0x00, 0x00, + 0x40, 0x32, 0x01, 0x80, 0x00, 0x00, + 0x80, 0x2c, 0x01, 0x40, 0x00, 0x00, + 0x0c, 0x90, 0x64, 0x80, 0x00, 0x00, + 0x05, 0x88, 0x2c, 0x40, 0x00, 0x00, + 0x62, 0x23, 0x11, 0x00, 0x00, 0x00, + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x22, 0x11, 0x10, 0x80, 0x00, 0x00, + 0x13, 0x40, 0x9a, 0x00, 0x00, 0x00, + 0x25, 0x01, 0x28, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xc0, 0xc0, 0x00, 0x00, + 0x0a, 0x20, 0x51, 0x00, 0x00, 0x00, + 0x88, 0x8c, 0x44, 0x40, 0x00, 0x00, + 0x06, 0x80, 0x34, 0x00, 0x00, 0x00, + 0xe0, 0x27, 0x01, 0x00, 0x00, 0x00, + 0x84, 0x44, 0x22, 0x00, 0x00, 0x00, + 0x44, 0x1a, 0x20, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_22[132] = { + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x22, 0x11, 0x10, 0x80, 0x00, 0x00, + 0x13, 0x40, 0x9a, 0x00, 0x00, 0x00, + 0x25, 0x01, 0x28, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xc0, 0xc0, 0x00, 0x00, + 0x0a, 0x20, 0x51, 0x00, 0x00, 0x00, + 0x88, 0x8c, 0x44, 0x40, 0x00, 0x00, + 0x06, 0x80, 0x34, 0x00, 0x00, 0x00, + 0xe0, 0x27, 0x01, 0x00, 0x00, 0x00, + 0x84, 0x44, 0x22, 0x00, 0x00, 0x00, + 0x44, 0x1a, 0x20, 0xc0, 0x00, 0x00, + 0xd1, 0x06, 0x88, 0x00, 0x00, 0x00, + 0x44, 0x52, 0x22, 0x80, 0x00, 0x00, + 0x10, 0x98, 0x84, 0xc0, 0x00, 0x00, + 0xa0, 0x55, 0x02, 0x80, 0x00, 0x00, + 0x4a, 0x0a, 0x50, 0x40, 0x00, 0x00, + 0x40, 0x32, 0x01, 0x80, 0x00, 0x00, + 0x80, 0x2c, 0x01, 0x40, 0x00, 0x00, + 0x0c, 0x90, 0x64, 0x80, 0x00, 0x00, + 0x05, 0x88, 0x2c, 0x40, 0x00, 0x00, + 0x62, 0x23, 0x11, 0x00, 0x00, 0x00, + 0x13, 0xc6, 0x6b, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_23[138] = { + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x22, 0x11, 0x10, 0x80, 0x00, 0x00, + 0x13, 0x40, 0x9a, 0x00, 0x00, 0x00, + 0x25, 0x01, 0x28, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xc0, 0xc0, 0x00, 0x00, + 0x0a, 0x20, 0x51, 0x00, 0x00, 0x00, + 0x88, 0x8c, 0x44, 0x40, 0x00, 0x00, + 0x06, 0x80, 0x34, 0x00, 0x00, 0x00, + 0xe0, 0x27, 0x01, 0x00, 0x00, 0x00, + 0x84, 0x44, 0x22, 0x00, 0x00, 0x00, + 0x44, 0x1a, 0x20, 0xc0, 0x00, 0x00, + 0x28, 0x29, 0x41, 0x40, 0x00, 0x00, + 0x84, 0x54, 0x22, 0x80, 0x00, 0x00, + 0x60, 0x43, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x02, 0x98, 0x14, 0xc0, 0x00, 0x00, + 0x01, 0x30, 0x09, 0x80, 0x00, 0x00, + 0x48, 0x12, 0x40, 0x80, 0x00, 0x00, + 0x24, 0x81, 0x24, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x04, 0x50, 0x00, 0x00, 0x00, + 0x11, 0x80, 0x8c, 0x00, 0x00, 0x00, + 0x52, 0x22, 0x91, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_24[144] = { + 0x28, 0x29, 0x41, 0x40, 0x00, 0x00, + 0x84, 0x54, 0x22, 0x80, 0x00, 0x00, + 0x60, 0x43, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x02, 0x98, 0x14, 0xc0, 0x00, 0x00, + 0x01, 0x30, 0x09, 0x80, 0x00, 0x00, + 0x48, 0x12, 0x40, 0x80, 0x00, 0x00, + 0x24, 0x81, 0x24, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x04, 0x50, 0x00, 0x00, 0x00, + 0x11, 0x80, 0x8c, 0x00, 0x00, 0x00, + 0x52, 0x22, 0x91, 0x00, 0x00, 0x00, + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x22, 0x11, 0x10, 0x80, 0x00, 0x00, + 0x13, 0x40, 0x9a, 0x00, 0x00, 0x00, + 0x25, 0x01, 0x28, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xc0, 0xc0, 0x00, 0x00, + 0x0a, 0x20, 0x51, 0x00, 0x00, 0x00, + 0x88, 0x8c, 0x44, 0x40, 0x00, 0x00, + 0x06, 0x80, 0x34, 0x00, 0x00, 0x00, + 0xe0, 0x27, 0x01, 0x00, 0x00, 0x00, + 0x84, 0x44, 0x22, 0x00, 0x00, 0x00, + 0x44, 0x1a, 0x20, 0xc0, 0x00, 0x00, + 0xdb, 0x4d, 0xd8, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_25[150] = { + 0x28, 0x29, 0x41, 0x40, 0x00, 0x00, + 0x84, 0x54, 0x22, 0x80, 0x00, 0x00, + 0x60, 0x43, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x02, 0x98, 0x14, 0xc0, 0x00, 0x00, + 0x01, 0x30, 0x09, 0x80, 0x00, 0x00, + 0x48, 0x12, 0x40, 0x80, 0x00, 0x00, + 0x24, 0x81, 0x24, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x04, 0x50, 0x00, 0x00, 0x00, + 0x11, 0x80, 0x8c, 0x00, 0x00, 0x00, + 0x52, 0x22, 0x91, 0x00, 0x00, 0x00, + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x81, 0x24, 0x09, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x30, 0x81, 0x84, 0x00, 0x00, 0x00, + 0x21, 0x11, 0x08, 0x80, 0x00, 0x00, + 0x03, 0xc0, 0x1e, 0x00, 0x00, 0x00, + 0xe8, 0x07, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x10, 0x50, 0x80, 0x00, 0x00, + 0x80, 0x1c, 0x00, 0xc0, 0x00, 0x00, + 0x04, 0x90, 0x24, 0x80, 0x00, 0x00, + 0x08, 0xa8, 0x45, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_26[156] = { + 0x51, 0x22, 0x89, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x81, 0x24, 0x09, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x30, 0x81, 0x84, 0x00, 0x00, 0x00, + 0x21, 0x11, 0x08, 0x80, 0x00, 0x00, + 0x03, 0xc0, 0x1e, 0x00, 0x00, 0x00, + 0xe8, 0x07, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x10, 0x50, 0x80, 0x00, 0x00, + 0x80, 0x1c, 0x00, 0xc0, 0x00, 0x00, + 0x04, 0x90, 0x24, 0x80, 0x00, 0x00, + 0x08, 0xa8, 0x45, 0x40, 0x00, 0x00, + 0x28, 0x29, 0x41, 0x40, 0x00, 0x00, + 0x84, 0x54, 0x22, 0x80, 0x00, 0x00, + 0x60, 0x43, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x48, 0x2a, 0x40, 0x00, 0x00, + 0x02, 0x98, 0x14, 0xc0, 0x00, 0x00, + 0x01, 0x30, 0x09, 0x80, 0x00, 0x00, + 0x48, 0x12, 0x40, 0x80, 0x00, 0x00, + 0x24, 0x81, 0x24, 0x00, 0x00, 0x00, + 0x94, 0x04, 0xa0, 0x00, 0x00, 0x00, + 0x8a, 0x04, 0x50, 0x00, 0x00, 0x00, + 0x11, 0x80, 0x8c, 0x00, 0x00, 0x00, + 0x52, 0x22, 0x91, 0x00, 0x00, 0x00, + 0xf9, 0x13, 0x51, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_3[18] = { + 0x99, 0xb4, 0xcd, 0x80, 0x00, 0x00, + 0x46, 0xda, 0x36, 0xc0, 0x00, 0x00, + 0x37, 0x29, 0xb9, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_4[24] = { + 0x49, 0xb2, 0x4d, 0x80, 0x00, 0x00, + 0x26, 0xd1, 0x36, 0x80, 0x00, 0x00, + 0x85, 0x6c, 0x2b, 0x40, 0x00, 0x00, + 0x52, 0x5a, 0x92, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_5[30] = { + 0x51, 0x32, 0x89, 0x80, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x0c, 0x68, 0x63, 0x40, 0x00, 0x00, + 0xa1, 0xc5, 0x0e, 0x00, 0x00, 0x00, + 0x22, 0x99, 0x14, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_6[36] = { + 0xd1, 0x26, 0x89, 0x00, 0x00, 0x00, + 0x46, 0xd2, 0x36, 0x80, 0x00, 0x00, + 0x15, 0x48, 0xaa, 0x40, 0x00, 0x00, + 0x21, 0x71, 0x0b, 0x80, 0x00, 0x00, + 0x28, 0xc9, 0x46, 0x40, 0x00, 0x00, + 0xaa, 0x25, 0x51, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_7[42] = { + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x26, 0x51, 0x32, 0x80, 0x00, 0x00, + 0xb1, 0x45, 0x8a, 0x00, 0x00, 0x00, + 0x2b, 0x09, 0x58, 0x40, 0x00, 0x00, + 0x14, 0xc8, 0xa6, 0x40, 0x00, 0x00, + 0xc8, 0x8e, 0x44, 0x40, 0x00, 0x00, + 0x84, 0xb4, 0x25, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_8[48] = { + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x30, 0x91, 0x84, 0x80, 0x00, 0x00, + 0x16, 0x08, 0xb0, 0x40, 0x00, 0x00, + 0x03, 0x30, 0x19, 0x80, 0x00, 0x00, + 0x44, 0x62, 0x23, 0x00, 0x00, 0x00, + 0x08, 0x18, 0x40, 0xc0, 0x00, 0x00, + 0xd8, 0x06, 0xc0, 0x00, 0x00, 0x00, + 0xa1, 0x45, 0x0a, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom26_9[54] = { + 0x59, 0x22, 0xc9, 0x00, 0x00, 0x00, + 0x66, 0x43, 0x32, 0x00, 0x00, 0x00, + 0x14, 0x40, 0xa2, 0x00, 0x00, 0x00, + 0x21, 0x49, 0x0a, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x16, 0x40, 0x00, 0x00, + 0x94, 0x14, 0xa0, 0x80, 0x00, 0x00, + 0x80, 0xac, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x90, 0x54, 0x80, 0x00, 0x00, + 0x40, 0x1a, 0x00, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_1[6] = { + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_10[60] = { + 0xd1, 0x06, 0x06, 0xa0, 0x00, 0x00, + 0x44, 0x50, 0xea, 0x00, 0x00, 0x00, + 0x10, 0x9e, 0xa0, 0x40, 0x00, 0x00, + 0xa0, 0x50, 0x13, 0x00, 0x00, 0x00, + 0x4a, 0x08, 0x21, 0x40, 0x00, 0x00, + 0x40, 0x31, 0x04, 0xc0, 0x00, 0x00, + 0x80, 0x2a, 0x02, 0x20, 0x00, 0x00, + 0x0c, 0x90, 0x44, 0x20, 0x00, 0x00, + 0x05, 0x8b, 0x40, 0x00, 0x00, 0x00, + 0x62, 0x21, 0x18, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_11[66] = { + 0x51, 0x23, 0x16, 0x80, 0x00, 0x00, + 0x22, 0x11, 0xa9, 0x00, 0x00, 0x00, + 0x13, 0x40, 0xa0, 0xa0, 0x00, 0x00, + 0x25, 0x06, 0x28, 0x40, 0x00, 0x00, + 0x18, 0x19, 0x10, 0x60, 0x00, 0x00, + 0x0a, 0x24, 0x45, 0xc0, 0x00, 0x00, + 0x88, 0x8a, 0x12, 0xa0, 0x00, 0x00, + 0x06, 0x81, 0x45, 0x20, 0x00, 0x00, + 0xe0, 0x24, 0xa1, 0x00, 0x00, 0x00, + 0x84, 0x40, 0xd8, 0x20, 0x00, 0x00, + 0x44, 0x19, 0x16, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_12[72] = { + 0x28, 0x2c, 0x08, 0x20, 0x00, 0x00, + 0x84, 0x52, 0x03, 0x40, 0x00, 0x00, + 0x60, 0x44, 0x81, 0x20, 0x00, 0x00, + 0x05, 0x49, 0x41, 0x40, 0x00, 0x00, + 0x02, 0x9a, 0x90, 0x80, 0x00, 0x00, + 0x01, 0x32, 0x0c, 0x40, 0x00, 0x00, + 0x48, 0x10, 0x49, 0x80, 0x00, 0x00, + 0x24, 0x82, 0x42, 0x20, 0x00, 0x00, + 0x94, 0x00, 0x22, 0x20, 0x00, 0x00, + 0x8a, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x11, 0x85, 0x2c, 0x80, 0x00, 0x00, + 0x52, 0x20, 0x90, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_13[78] = { + 0x51, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x05, 0x4a, 0x40, 0x20, 0x00, 0x00, + 0x81, 0x20, 0x05, 0x60, 0x00, 0x00, + 0x94, 0x01, 0x40, 0x40, 0x00, 0x00, + 0x30, 0x84, 0x08, 0x40, 0x00, 0x00, + 0x21, 0x11, 0x18, 0x20, 0x00, 0x00, + 0x03, 0xc0, 0x34, 0x00, 0x00, 0x00, + 0xe8, 0x04, 0x00, 0xa0, 0x00, 0x00, + 0x0a, 0x11, 0x80, 0x80, 0x00, 0x00, + 0x80, 0x1c, 0x61, 0x00, 0x00, 0x00, + 0x04, 0x92, 0xa0, 0x00, 0x00, 0x00, + 0x08, 0xac, 0x06, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_14[84] = { + 0x59, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x26, 0x55, 0xc9, 0x00, 0x00, 0x00, + 0xb1, 0x40, 0xc5, 0xa0, 0x00, 0x00, + 0x2b, 0x0a, 0xa4, 0xc0, 0x00, 0x00, + 0x14, 0xc8, 0x33, 0x60, 0x00, 0x00, + 0xc8, 0x8c, 0x2a, 0xa0, 0x00, 0x00, + 0x84, 0xb5, 0x54, 0x40, 0x00, 0x00, + 0xd1, 0x22, 0x52, 0xa0, 0x00, 0x00, + 0x46, 0xd4, 0xaa, 0x40, 0x00, 0x00, + 0x15, 0x48, 0xa5, 0xa0, 0x00, 0x00, + 0x21, 0x72, 0x8d, 0x40, 0x00, 0x00, + 0x28, 0xc9, 0x13, 0x60, 0x00, 0x00, + 0xaa, 0x24, 0x44, 0x60, 0x00, 0x00, + 0x0a, 0xe7, 0x3b, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_15[90] = { + 0x59, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x26, 0x55, 0xc9, 0x00, 0x00, 0x00, + 0xb1, 0x40, 0xc5, 0xa0, 0x00, 0x00, + 0x2b, 0x0a, 0xa4, 0xc0, 0x00, 0x00, + 0x14, 0xc8, 0x33, 0x60, 0x00, 0x00, + 0xc8, 0x8c, 0x2a, 0xa0, 0x00, 0x00, + 0x84, 0xb5, 0x54, 0x40, 0x00, 0x00, + 0x80, 0xae, 0x00, 0xa0, 0x00, 0x00, + 0x30, 0x92, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x0c, 0x41, 0x80, 0x00, 0x00, + 0x03, 0x31, 0x05, 0x20, 0x00, 0x00, + 0x44, 0x60, 0x52, 0x40, 0x00, 0x00, + 0x08, 0x18, 0x24, 0xc0, 0x00, 0x00, + 0xd8, 0x04, 0xa2, 0x00, 0x00, 0x00, + 0xa1, 0x43, 0x90, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_16[96] = { + 0x80, 0xae, 0x00, 0xa0, 0x00, 0x00, + 0x30, 0x92, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x0c, 0x41, 0x80, 0x00, 0x00, + 0x03, 0x31, 0x05, 0x20, 0x00, 0x00, + 0x44, 0x60, 0x52, 0x40, 0x00, 0x00, + 0x08, 0x18, 0x24, 0xc0, 0x00, 0x00, + 0xd8, 0x04, 0xa2, 0x00, 0x00, 0x00, + 0xa1, 0x43, 0x90, 0x00, 0x00, 0x00, + 0x59, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x26, 0x55, 0xc9, 0x00, 0x00, 0x00, + 0xb1, 0x40, 0xc5, 0xa0, 0x00, 0x00, + 0x2b, 0x0a, 0xa4, 0xc0, 0x00, 0x00, + 0x14, 0xc8, 0x33, 0x60, 0x00, 0x00, + 0xc8, 0x8c, 0x2a, 0xa0, 0x00, 0x00, + 0x84, 0xb5, 0x54, 0x40, 0x00, 0x00, + 0x01, 0x50, 0xfb, 0xe0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_17[102] = { + 0x80, 0xae, 0x00, 0xa0, 0x00, 0x00, + 0x30, 0x92, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x0c, 0x41, 0x80, 0x00, 0x00, + 0x03, 0x31, 0x05, 0x20, 0x00, 0x00, + 0x44, 0x60, 0x52, 0x40, 0x00, 0x00, + 0x08, 0x18, 0x24, 0xc0, 0x00, 0x00, + 0xd8, 0x04, 0xa2, 0x00, 0x00, 0x00, + 0xa1, 0x43, 0x90, 0x00, 0x00, 0x00, + 0x59, 0x25, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x14, 0x42, 0x51, 0x20, 0x00, 0x00, + 0x21, 0x49, 0x05, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x8c, 0x20, 0x00, 0x00, + 0x94, 0x12, 0x48, 0x40, 0x00, 0x00, + 0x80, 0xac, 0x30, 0x60, 0x00, 0x00, + 0x0a, 0x91, 0x06, 0xa0, 0x00, 0x00, + 0x40, 0x1c, 0x42, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_18[108] = { + 0x59, 0x25, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x14, 0x42, 0x51, 0x20, 0x00, 0x00, + 0x21, 0x49, 0x05, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x8c, 0x20, 0x00, 0x00, + 0x94, 0x12, 0x48, 0x40, 0x00, 0x00, + 0x80, 0xac, 0x30, 0x60, 0x00, 0x00, + 0x0a, 0x91, 0x06, 0xa0, 0x00, 0x00, + 0x40, 0x1c, 0x42, 0x40, 0x00, 0x00, + 0x80, 0xae, 0x00, 0xa0, 0x00, 0x00, + 0x30, 0x92, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x0c, 0x41, 0x80, 0x00, 0x00, + 0x03, 0x31, 0x05, 0x20, 0x00, 0x00, + 0x44, 0x60, 0x52, 0x40, 0x00, 0x00, + 0x08, 0x18, 0x24, 0xc0, 0x00, 0x00, + 0xd8, 0x04, 0xa2, 0x00, 0x00, 0x00, + 0xa1, 0x43, 0x90, 0x00, 0x00, 0x00, + 0x53, 0xc3, 0x33, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_19[114] = { + 0x59, 0x25, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x14, 0x42, 0x51, 0x20, 0x00, 0x00, + 0x21, 0x49, 0x05, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x8c, 0x20, 0x00, 0x00, + 0x94, 0x12, 0x48, 0x40, 0x00, 0x00, + 0x80, 0xac, 0x30, 0x60, 0x00, 0x00, + 0x0a, 0x91, 0x06, 0xa0, 0x00, 0x00, + 0x40, 0x1c, 0x42, 0x40, 0x00, 0x00, + 0xd1, 0x06, 0x06, 0xa0, 0x00, 0x00, + 0x44, 0x50, 0xea, 0x00, 0x00, 0x00, + 0x10, 0x9e, 0xa0, 0x40, 0x00, 0x00, + 0xa0, 0x50, 0x13, 0x00, 0x00, 0x00, + 0x4a, 0x08, 0x21, 0x40, 0x00, 0x00, + 0x40, 0x31, 0x04, 0xc0, 0x00, 0x00, + 0x80, 0x2a, 0x02, 0x20, 0x00, 0x00, + 0x0c, 0x90, 0x44, 0x20, 0x00, 0x00, + 0x05, 0x8b, 0x40, 0x00, 0x00, 0x00, + 0x62, 0x21, 0x18, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_2[12] = { + 0xec, 0xc7, 0x67, 0x40, 0x00, 0x00, + 0x1b, 0x39, 0xdc, 0xe0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_20[120] = { + 0xd1, 0x06, 0x06, 0xa0, 0x00, 0x00, + 0x44, 0x50, 0xea, 0x00, 0x00, 0x00, + 0x10, 0x9e, 0xa0, 0x40, 0x00, 0x00, + 0xa0, 0x50, 0x13, 0x00, 0x00, 0x00, + 0x4a, 0x08, 0x21, 0x40, 0x00, 0x00, + 0x40, 0x31, 0x04, 0xc0, 0x00, 0x00, + 0x80, 0x2a, 0x02, 0x20, 0x00, 0x00, + 0x0c, 0x90, 0x44, 0x20, 0x00, 0x00, + 0x05, 0x8b, 0x40, 0x00, 0x00, 0x00, + 0x62, 0x21, 0x18, 0x80, 0x00, 0x00, + 0x59, 0x25, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x14, 0x42, 0x51, 0x20, 0x00, 0x00, + 0x21, 0x49, 0x05, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x8c, 0x20, 0x00, 0x00, + 0x94, 0x12, 0x48, 0x40, 0x00, 0x00, + 0x80, 0xac, 0x30, 0x60, 0x00, 0x00, + 0x0a, 0x91, 0x06, 0xa0, 0x00, 0x00, + 0x40, 0x1c, 0x42, 0x40, 0x00, 0x00, + 0xcb, 0xff, 0x6f, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_21[126] = { + 0xd1, 0x06, 0x06, 0xa0, 0x00, 0x00, + 0x44, 0x50, 0xea, 0x00, 0x00, 0x00, + 0x10, 0x9e, 0xa0, 0x40, 0x00, 0x00, + 0xa0, 0x50, 0x13, 0x00, 0x00, 0x00, + 0x4a, 0x08, 0x21, 0x40, 0x00, 0x00, + 0x40, 0x31, 0x04, 0xc0, 0x00, 0x00, + 0x80, 0x2a, 0x02, 0x20, 0x00, 0x00, + 0x0c, 0x90, 0x44, 0x20, 0x00, 0x00, + 0x05, 0x8b, 0x40, 0x00, 0x00, 0x00, + 0x62, 0x21, 0x18, 0x80, 0x00, 0x00, + 0x51, 0x23, 0x16, 0x80, 0x00, 0x00, + 0x22, 0x11, 0xa9, 0x00, 0x00, 0x00, + 0x13, 0x40, 0xa0, 0xa0, 0x00, 0x00, + 0x25, 0x06, 0x28, 0x40, 0x00, 0x00, + 0x18, 0x19, 0x10, 0x60, 0x00, 0x00, + 0x0a, 0x24, 0x45, 0xc0, 0x00, 0x00, + 0x88, 0x8a, 0x12, 0xa0, 0x00, 0x00, + 0x06, 0x81, 0x45, 0x20, 0x00, 0x00, + 0xe0, 0x24, 0xa1, 0x00, 0x00, 0x00, + 0x84, 0x40, 0xd8, 0x20, 0x00, 0x00, + 0x44, 0x19, 0x16, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_22[132] = { + 0x51, 0x23, 0x16, 0x80, 0x00, 0x00, + 0x22, 0x11, 0xa9, 0x00, 0x00, 0x00, + 0x13, 0x40, 0xa0, 0xa0, 0x00, 0x00, + 0x25, 0x06, 0x28, 0x40, 0x00, 0x00, + 0x18, 0x19, 0x10, 0x60, 0x00, 0x00, + 0x0a, 0x24, 0x45, 0xc0, 0x00, 0x00, + 0x88, 0x8a, 0x12, 0xa0, 0x00, 0x00, + 0x06, 0x81, 0x45, 0x20, 0x00, 0x00, + 0xe0, 0x24, 0xa1, 0x00, 0x00, 0x00, + 0x84, 0x40, 0xd8, 0x20, 0x00, 0x00, + 0x44, 0x19, 0x16, 0x00, 0x00, 0x00, + 0xd1, 0x06, 0x06, 0xa0, 0x00, 0x00, + 0x44, 0x50, 0xea, 0x00, 0x00, 0x00, + 0x10, 0x9e, 0xa0, 0x40, 0x00, 0x00, + 0xa0, 0x50, 0x13, 0x00, 0x00, 0x00, + 0x4a, 0x08, 0x21, 0x40, 0x00, 0x00, + 0x40, 0x31, 0x04, 0xc0, 0x00, 0x00, + 0x80, 0x2a, 0x02, 0x20, 0x00, 0x00, + 0x0c, 0x90, 0x44, 0x20, 0x00, 0x00, + 0x05, 0x8b, 0x40, 0x00, 0x00, 0x00, + 0x62, 0x21, 0x18, 0x80, 0x00, 0x00, + 0xf5, 0x2d, 0x52, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_23[138] = { + 0x51, 0x23, 0x16, 0x80, 0x00, 0x00, + 0x22, 0x11, 0xa9, 0x00, 0x00, 0x00, + 0x13, 0x40, 0xa0, 0xa0, 0x00, 0x00, + 0x25, 0x06, 0x28, 0x40, 0x00, 0x00, + 0x18, 0x19, 0x10, 0x60, 0x00, 0x00, + 0x0a, 0x24, 0x45, 0xc0, 0x00, 0x00, + 0x88, 0x8a, 0x12, 0xa0, 0x00, 0x00, + 0x06, 0x81, 0x45, 0x20, 0x00, 0x00, + 0xe0, 0x24, 0xa1, 0x00, 0x00, 0x00, + 0x84, 0x40, 0xd8, 0x20, 0x00, 0x00, + 0x44, 0x19, 0x16, 0x00, 0x00, 0x00, + 0x28, 0x2c, 0x08, 0x20, 0x00, 0x00, + 0x84, 0x52, 0x03, 0x40, 0x00, 0x00, + 0x60, 0x44, 0x81, 0x20, 0x00, 0x00, + 0x05, 0x49, 0x41, 0x40, 0x00, 0x00, + 0x02, 0x9a, 0x90, 0x80, 0x00, 0x00, + 0x01, 0x32, 0x0c, 0x40, 0x00, 0x00, + 0x48, 0x10, 0x49, 0x80, 0x00, 0x00, + 0x24, 0x82, 0x42, 0x20, 0x00, 0x00, + 0x94, 0x00, 0x22, 0x20, 0x00, 0x00, + 0x8a, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x11, 0x85, 0x2c, 0x80, 0x00, 0x00, + 0x52, 0x20, 0x90, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_24[144] = { + 0x28, 0x2c, 0x08, 0x20, 0x00, 0x00, + 0x84, 0x52, 0x03, 0x40, 0x00, 0x00, + 0x60, 0x44, 0x81, 0x20, 0x00, 0x00, + 0x05, 0x49, 0x41, 0x40, 0x00, 0x00, + 0x02, 0x9a, 0x90, 0x80, 0x00, 0x00, + 0x01, 0x32, 0x0c, 0x40, 0x00, 0x00, + 0x48, 0x10, 0x49, 0x80, 0x00, 0x00, + 0x24, 0x82, 0x42, 0x20, 0x00, 0x00, + 0x94, 0x00, 0x22, 0x20, 0x00, 0x00, + 0x8a, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x11, 0x85, 0x2c, 0x80, 0x00, 0x00, + 0x52, 0x20, 0x90, 0x60, 0x00, 0x00, + 0x51, 0x23, 0x16, 0x80, 0x00, 0x00, + 0x22, 0x11, 0xa9, 0x00, 0x00, 0x00, + 0x13, 0x40, 0xa0, 0xa0, 0x00, 0x00, + 0x25, 0x06, 0x28, 0x40, 0x00, 0x00, + 0x18, 0x19, 0x10, 0x60, 0x00, 0x00, + 0x0a, 0x24, 0x45, 0xc0, 0x00, 0x00, + 0x88, 0x8a, 0x12, 0xa0, 0x00, 0x00, + 0x06, 0x81, 0x45, 0x20, 0x00, 0x00, + 0xe0, 0x24, 0xa1, 0x00, 0x00, 0x00, + 0x84, 0x40, 0xd8, 0x20, 0x00, 0x00, + 0x44, 0x19, 0x16, 0x00, 0x00, 0x00, + 0xa2, 0x85, 0xdb, 0xa0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_25[150] = { + 0x28, 0x2c, 0x08, 0x20, 0x00, 0x00, + 0x84, 0x52, 0x03, 0x40, 0x00, 0x00, + 0x60, 0x44, 0x81, 0x20, 0x00, 0x00, + 0x05, 0x49, 0x41, 0x40, 0x00, 0x00, + 0x02, 0x9a, 0x90, 0x80, 0x00, 0x00, + 0x01, 0x32, 0x0c, 0x40, 0x00, 0x00, + 0x48, 0x10, 0x49, 0x80, 0x00, 0x00, + 0x24, 0x82, 0x42, 0x20, 0x00, 0x00, + 0x94, 0x00, 0x22, 0x20, 0x00, 0x00, + 0x8a, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x11, 0x85, 0x2c, 0x80, 0x00, 0x00, + 0x52, 0x20, 0x90, 0x60, 0x00, 0x00, + 0x51, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x05, 0x4a, 0x40, 0x20, 0x00, 0x00, + 0x81, 0x20, 0x05, 0x60, 0x00, 0x00, + 0x94, 0x01, 0x40, 0x40, 0x00, 0x00, + 0x30, 0x84, 0x08, 0x40, 0x00, 0x00, + 0x21, 0x11, 0x18, 0x20, 0x00, 0x00, + 0x03, 0xc0, 0x34, 0x00, 0x00, 0x00, + 0xe8, 0x04, 0x00, 0xa0, 0x00, 0x00, + 0x0a, 0x11, 0x80, 0x80, 0x00, 0x00, + 0x80, 0x1c, 0x61, 0x00, 0x00, 0x00, + 0x04, 0x92, 0xa0, 0x00, 0x00, 0x00, + 0x08, 0xac, 0x06, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_26[156] = { + 0x51, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x05, 0x4a, 0x40, 0x20, 0x00, 0x00, + 0x81, 0x20, 0x05, 0x60, 0x00, 0x00, + 0x94, 0x01, 0x40, 0x40, 0x00, 0x00, + 0x30, 0x84, 0x08, 0x40, 0x00, 0x00, + 0x21, 0x11, 0x18, 0x20, 0x00, 0x00, + 0x03, 0xc0, 0x34, 0x00, 0x00, 0x00, + 0xe8, 0x04, 0x00, 0xa0, 0x00, 0x00, + 0x0a, 0x11, 0x80, 0x80, 0x00, 0x00, + 0x80, 0x1c, 0x61, 0x00, 0x00, 0x00, + 0x04, 0x92, 0xa0, 0x00, 0x00, 0x00, + 0x08, 0xac, 0x06, 0x00, 0x00, 0x00, + 0x28, 0x2c, 0x08, 0x20, 0x00, 0x00, + 0x84, 0x52, 0x03, 0x40, 0x00, 0x00, + 0x60, 0x44, 0x81, 0x20, 0x00, 0x00, + 0x05, 0x49, 0x41, 0x40, 0x00, 0x00, + 0x02, 0x9a, 0x90, 0x80, 0x00, 0x00, + 0x01, 0x32, 0x0c, 0x40, 0x00, 0x00, + 0x48, 0x10, 0x49, 0x80, 0x00, 0x00, + 0x24, 0x82, 0x42, 0x20, 0x00, 0x00, + 0x94, 0x00, 0x22, 0x20, 0x00, 0x00, + 0x8a, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x11, 0x85, 0x2c, 0x80, 0x00, 0x00, + 0x52, 0x20, 0x90, 0x60, 0x00, 0x00, + 0xcd, 0x41, 0xa2, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_27[162] = { + 0x51, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x05, 0x4a, 0x40, 0x20, 0x00, 0x00, + 0x81, 0x20, 0x05, 0x60, 0x00, 0x00, + 0x94, 0x01, 0x40, 0x40, 0x00, 0x00, + 0x30, 0x84, 0x08, 0x40, 0x00, 0x00, + 0x21, 0x11, 0x18, 0x20, 0x00, 0x00, + 0x03, 0xc0, 0x34, 0x00, 0x00, 0x00, + 0xe8, 0x04, 0x00, 0xa0, 0x00, 0x00, + 0x0a, 0x11, 0x80, 0x80, 0x00, 0x00, + 0x80, 0x1c, 0x61, 0x00, 0x00, 0x00, + 0x04, 0x92, 0xa0, 0x00, 0x00, 0x00, + 0x08, 0xac, 0x06, 0x00, 0x00, 0x00, + 0x51, 0x22, 0x02, 0xa0, 0x00, 0x00, + 0x66, 0x40, 0xaa, 0x00, 0x00, 0x00, + 0x05, 0x4e, 0x00, 0x20, 0x00, 0x00, + 0x81, 0x21, 0x40, 0x80, 0x00, 0x00, + 0x94, 0x00, 0x28, 0x60, 0x00, 0x00, + 0x30, 0x83, 0x24, 0x00, 0x00, 0x00, + 0x21, 0x14, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0xc0, 0x84, 0xc0, 0x00, 0x00, + 0xe8, 0x04, 0x21, 0x00, 0x00, 0x00, + 0x0a, 0x10, 0x91, 0x80, 0x00, 0x00, + 0x80, 0x1b, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x91, 0x43, 0x00, 0x00, 0x00, + 0x08, 0xa8, 0x70, 0x40, 0x00, 0x00, + 0x9c, 0xc0, 0x84, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_3[18] = { + 0x99, 0xb5, 0x66, 0xc0, 0x00, 0x00, + 0x46, 0xda, 0xab, 0x60, 0x00, 0x00, + 0x37, 0x29, 0x3d, 0xa0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_4[24] = { + 0x49, 0xb1, 0x66, 0xc0, 0x00, 0x00, + 0x26, 0xd4, 0x9b, 0x40, 0x00, 0x00, + 0x85, 0x68, 0xd5, 0xa0, 0x00, 0x00, + 0x52, 0x5a, 0x39, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_5[30] = { + 0x51, 0x33, 0x26, 0xc0, 0x00, 0x00, + 0x66, 0x45, 0x2b, 0x40, 0x00, 0x00, + 0x0c, 0x6a, 0x95, 0xa0, 0x00, 0x00, + 0xa1, 0xc0, 0xed, 0x40, 0x00, 0x00, + 0x22, 0x9c, 0xe2, 0xa0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_6[36] = { + 0xd1, 0x22, 0x52, 0xa0, 0x00, 0x00, + 0x46, 0xd4, 0xaa, 0x40, 0x00, 0x00, + 0x15, 0x48, 0xa5, 0xa0, 0x00, 0x00, + 0x21, 0x72, 0x8d, 0x40, 0x00, 0x00, + 0x28, 0xc9, 0x13, 0x60, 0x00, 0x00, + 0xaa, 0x24, 0x44, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_7[42] = { + 0x59, 0x23, 0x12, 0xa0, 0x00, 0x00, + 0x26, 0x55, 0xc9, 0x00, 0x00, 0x00, + 0xb1, 0x40, 0xc5, 0xa0, 0x00, 0x00, + 0x2b, 0x0a, 0xa4, 0xc0, 0x00, 0x00, + 0x14, 0xc8, 0x33, 0x60, 0x00, 0x00, + 0xc8, 0x8c, 0x2a, 0xa0, 0x00, 0x00, + 0x84, 0xb5, 0x54, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_8[48] = { + 0x80, 0xae, 0x00, 0xa0, 0x00, 0x00, + 0x30, 0x92, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x0c, 0x41, 0x80, 0x00, 0x00, + 0x03, 0x31, 0x05, 0x20, 0x00, 0x00, + 0x44, 0x60, 0x52, 0x40, 0x00, 0x00, + 0x08, 0x18, 0x24, 0xc0, 0x00, 0x00, + 0xd8, 0x04, 0xa2, 0x00, 0x00, 0x00, + 0xa1, 0x43, 0x90, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom27_9[54] = { + 0x59, 0x25, 0x12, 0xa0, 0x00, 0x00, + 0x66, 0x41, 0xa3, 0x00, 0x00, 0x00, + 0x14, 0x42, 0x51, 0x20, 0x00, 0x00, + 0x21, 0x49, 0x05, 0x40, 0x00, 0x00, + 0x02, 0xc8, 0x8c, 0x20, 0x00, 0x00, + 0x94, 0x12, 0x48, 0x40, 0x00, 0x00, + 0x80, 0xac, 0x30, 0x60, 0x00, 0x00, + 0x0a, 0x91, 0x06, 0xa0, 0x00, 0x00, + 0x40, 0x1c, 0x42, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_1[6] = { + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_10[60] = { + 0xc0, 0xd7, 0x03, 0x50, 0x00, 0x00, + 0x1d, 0x40, 0x75, 0x00, 0x00, 0x00, + 0xd4, 0x0b, 0x50, 0x20, 0x00, 0x00, + 0x02, 0x60, 0x09, 0x80, 0x00, 0x00, + 0x04, 0x28, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0x98, 0x82, 0x60, 0x00, 0x00, + 0x40, 0x45, 0x01, 0x10, 0x00, 0x00, + 0x08, 0x84, 0x22, 0x10, 0x00, 0x00, + 0x68, 0x01, 0xa0, 0x00, 0x00, 0x00, + 0x23, 0x10, 0x8c, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_11[66] = { + 0x62, 0xd1, 0x8b, 0x40, 0x00, 0x00, + 0x35, 0x20, 0xd4, 0x80, 0x00, 0x00, + 0x14, 0x14, 0x50, 0x50, 0x00, 0x00, + 0xc5, 0x0b, 0x14, 0x20, 0x00, 0x00, + 0x22, 0x0c, 0x88, 0x30, 0x00, 0x00, + 0x88, 0xba, 0x22, 0xe0, 0x00, 0x00, + 0x42, 0x55, 0x09, 0x50, 0x00, 0x00, + 0x28, 0xa4, 0xa2, 0x90, 0x00, 0x00, + 0x94, 0x22, 0x50, 0x80, 0x00, 0x00, + 0x1b, 0x04, 0x6c, 0x10, 0x00, 0x00, + 0x22, 0xc0, 0x8b, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_12[72] = { + 0x81, 0x06, 0x04, 0x10, 0x00, 0x00, + 0x40, 0x69, 0x01, 0xa0, 0x00, 0x00, + 0x90, 0x26, 0x40, 0x90, 0x00, 0x00, + 0x28, 0x28, 0xa0, 0xa0, 0x00, 0x00, + 0x52, 0x11, 0x48, 0x40, 0x00, 0x00, + 0x41, 0x89, 0x06, 0x20, 0x00, 0x00, + 0x09, 0x30, 0x24, 0xc0, 0x00, 0x00, + 0x48, 0x45, 0x21, 0x10, 0x00, 0x00, + 0x04, 0x44, 0x11, 0x10, 0x00, 0x00, + 0x0e, 0x80, 0x3a, 0x00, 0x00, 0x00, + 0xa5, 0x92, 0x96, 0x40, 0x00, 0x00, + 0x12, 0x0c, 0x48, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_13[78] = { + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x48, 0x05, 0x20, 0x10, 0x00, 0x00, + 0x00, 0xac, 0x02, 0xb0, 0x00, 0x00, + 0x28, 0x08, 0xa0, 0x20, 0x00, 0x00, + 0x81, 0x0a, 0x04, 0x20, 0x00, 0x00, + 0x23, 0x04, 0x8c, 0x10, 0x00, 0x00, + 0x06, 0x80, 0x1a, 0x00, 0x00, 0x00, + 0x80, 0x16, 0x00, 0x50, 0x00, 0x00, + 0x30, 0x10, 0xc0, 0x40, 0x00, 0x00, + 0x8c, 0x22, 0x30, 0x80, 0x00, 0x00, + 0x54, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x80, 0xc2, 0x03, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_14[84] = { + 0x40, 0x55, 0x01, 0x50, 0x00, 0x00, + 0x15, 0x40, 0x55, 0x00, 0x00, 0x00, + 0xc0, 0x07, 0x00, 0x10, 0x00, 0x00, + 0x28, 0x10, 0xa0, 0x40, 0x00, 0x00, + 0x05, 0x0c, 0x14, 0x30, 0x00, 0x00, + 0x64, 0x81, 0x92, 0x00, 0x00, 0x00, + 0x81, 0x82, 0x06, 0x00, 0x00, 0x00, + 0x10, 0x98, 0x42, 0x60, 0x00, 0x00, + 0x84, 0x22, 0x10, 0x80, 0x00, 0x00, + 0x12, 0x30, 0x48, 0xc0, 0x00, 0x00, + 0x62, 0x01, 0x88, 0x00, 0x00, 0x00, + 0x28, 0x60, 0xa1, 0x80, 0x00, 0x00, + 0x0e, 0x08, 0x38, 0x20, 0x00, 0x00, + 0x10, 0x84, 0x42, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_15[90] = { + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0xb9, 0x22, 0xe4, 0x80, 0x00, 0x00, + 0x18, 0xb4, 0x62, 0xd0, 0x00, 0x00, + 0x54, 0x99, 0x52, 0x60, 0x00, 0x00, + 0x06, 0x6c, 0x19, 0xb0, 0x00, 0x00, + 0x85, 0x56, 0x15, 0x50, 0x00, 0x00, + 0xaa, 0x8a, 0xaa, 0x20, 0x00, 0x00, + 0xc0, 0x17, 0x00, 0x50, 0x00, 0x00, + 0x41, 0x61, 0x05, 0x80, 0x00, 0x00, + 0x88, 0x32, 0x20, 0xc0, 0x00, 0x00, + 0x20, 0xa4, 0x82, 0x90, 0x00, 0x00, + 0x0a, 0x48, 0x29, 0x20, 0x00, 0x00, + 0x04, 0x98, 0x12, 0x60, 0x00, 0x00, + 0x94, 0x42, 0x51, 0x00, 0x00, 0x00, + 0x72, 0x01, 0xc8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_16[96] = { + 0xc0, 0x17, 0x00, 0x50, 0x00, 0x00, + 0x41, 0x61, 0x05, 0x80, 0x00, 0x00, + 0x88, 0x32, 0x20, 0xc0, 0x00, 0x00, + 0x20, 0xa4, 0x82, 0x90, 0x00, 0x00, + 0x0a, 0x48, 0x29, 0x20, 0x00, 0x00, + 0x04, 0x98, 0x12, 0x60, 0x00, 0x00, + 0x94, 0x42, 0x51, 0x00, 0x00, 0x00, + 0x72, 0x01, 0xc8, 0x00, 0x00, 0x00, + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0xb9, 0x22, 0xe4, 0x80, 0x00, 0x00, + 0x18, 0xb4, 0x62, 0xd0, 0x00, 0x00, + 0x54, 0x99, 0x52, 0x60, 0x00, 0x00, + 0x06, 0x6c, 0x19, 0xb0, 0x00, 0x00, + 0x85, 0x56, 0x15, 0x50, 0x00, 0x00, + 0xaa, 0x8a, 0xaa, 0x20, 0x00, 0x00, + 0xed, 0x76, 0x36, 0x50, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_17[102] = { + 0xc0, 0x17, 0x00, 0x50, 0x00, 0x00, + 0x41, 0x61, 0x05, 0x80, 0x00, 0x00, + 0x88, 0x32, 0x20, 0xc0, 0x00, 0x00, + 0x20, 0xa4, 0x82, 0x90, 0x00, 0x00, + 0x0a, 0x48, 0x29, 0x20, 0x00, 0x00, + 0x04, 0x98, 0x12, 0x60, 0x00, 0x00, + 0x94, 0x42, 0x51, 0x00, 0x00, 0x00, + 0x72, 0x01, 0xc8, 0x00, 0x00, 0x00, + 0xa2, 0x56, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x4a, 0x25, 0x28, 0x90, 0x00, 0x00, + 0x20, 0xa8, 0x82, 0xa0, 0x00, 0x00, + 0x11, 0x84, 0x46, 0x10, 0x00, 0x00, + 0x49, 0x09, 0x24, 0x20, 0x00, 0x00, + 0x86, 0x0e, 0x18, 0x30, 0x00, 0x00, + 0x20, 0xd4, 0x83, 0x50, 0x00, 0x00, + 0x88, 0x4a, 0x21, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_18[108] = { + 0xa2, 0x56, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x4a, 0x25, 0x28, 0x90, 0x00, 0x00, + 0x20, 0xa8, 0x82, 0xa0, 0x00, 0x00, + 0x11, 0x84, 0x46, 0x10, 0x00, 0x00, + 0x49, 0x09, 0x24, 0x20, 0x00, 0x00, + 0x86, 0x0e, 0x18, 0x30, 0x00, 0x00, + 0x20, 0xd4, 0x83, 0x50, 0x00, 0x00, + 0x88, 0x4a, 0x21, 0x20, 0x00, 0x00, + 0xc0, 0x17, 0x00, 0x50, 0x00, 0x00, + 0x41, 0x61, 0x05, 0x80, 0x00, 0x00, + 0x88, 0x32, 0x20, 0xc0, 0x00, 0x00, + 0x20, 0xa4, 0x82, 0x90, 0x00, 0x00, + 0x0a, 0x48, 0x29, 0x20, 0x00, 0x00, + 0x04, 0x98, 0x12, 0x60, 0x00, 0x00, + 0x94, 0x42, 0x51, 0x00, 0x00, 0x00, + 0x72, 0x01, 0xc8, 0x00, 0x00, 0x00, + 0x6e, 0x9f, 0x98, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_19[114] = { + 0xa2, 0x56, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x4a, 0x25, 0x28, 0x90, 0x00, 0x00, + 0x20, 0xa8, 0x82, 0xa0, 0x00, 0x00, + 0x11, 0x84, 0x46, 0x10, 0x00, 0x00, + 0x49, 0x09, 0x24, 0x20, 0x00, 0x00, + 0x86, 0x0e, 0x18, 0x30, 0x00, 0x00, + 0x20, 0xd4, 0x83, 0x50, 0x00, 0x00, + 0x88, 0x4a, 0x21, 0x20, 0x00, 0x00, + 0xc0, 0xd7, 0x03, 0x50, 0x00, 0x00, + 0x1d, 0x40, 0x75, 0x00, 0x00, 0x00, + 0xd4, 0x0b, 0x50, 0x20, 0x00, 0x00, + 0x02, 0x60, 0x09, 0x80, 0x00, 0x00, + 0x04, 0x28, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0x98, 0x82, 0x60, 0x00, 0x00, + 0x40, 0x45, 0x01, 0x10, 0x00, 0x00, + 0x08, 0x84, 0x22, 0x10, 0x00, 0x00, + 0x68, 0x01, 0xa0, 0x00, 0x00, 0x00, + 0x23, 0x10, 0x8c, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_2[12] = { + 0xec, 0xeb, 0xb3, 0xa0, 0x00, 0x00, + 0x3b, 0x9c, 0xee, 0x70, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_20[120] = { + 0xc0, 0xd7, 0x03, 0x50, 0x00, 0x00, + 0x1d, 0x40, 0x75, 0x00, 0x00, 0x00, + 0xd4, 0x0b, 0x50, 0x20, 0x00, 0x00, + 0x02, 0x60, 0x09, 0x80, 0x00, 0x00, + 0x04, 0x28, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0x98, 0x82, 0x60, 0x00, 0x00, + 0x40, 0x45, 0x01, 0x10, 0x00, 0x00, + 0x08, 0x84, 0x22, 0x10, 0x00, 0x00, + 0x68, 0x01, 0xa0, 0x00, 0x00, 0x00, + 0x23, 0x10, 0x8c, 0x40, 0x00, 0x00, + 0xa2, 0x56, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x4a, 0x25, 0x28, 0x90, 0x00, 0x00, + 0x20, 0xa8, 0x82, 0xa0, 0x00, 0x00, + 0x11, 0x84, 0x46, 0x10, 0x00, 0x00, + 0x49, 0x09, 0x24, 0x20, 0x00, 0x00, + 0x86, 0x0e, 0x18, 0x30, 0x00, 0x00, + 0x20, 0xd4, 0x83, 0x50, 0x00, 0x00, + 0x88, 0x4a, 0x21, 0x20, 0x00, 0x00, + 0xea, 0x1b, 0x3a, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_21[126] = { + 0xc0, 0xd7, 0x03, 0x50, 0x00, 0x00, + 0x1d, 0x40, 0x75, 0x00, 0x00, 0x00, + 0xd4, 0x0b, 0x50, 0x20, 0x00, 0x00, + 0x02, 0x60, 0x09, 0x80, 0x00, 0x00, + 0x04, 0x28, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0x98, 0x82, 0x60, 0x00, 0x00, + 0x40, 0x45, 0x01, 0x10, 0x00, 0x00, + 0x08, 0x84, 0x22, 0x10, 0x00, 0x00, + 0x68, 0x01, 0xa0, 0x00, 0x00, 0x00, + 0x23, 0x10, 0x8c, 0x40, 0x00, 0x00, + 0x62, 0xd1, 0x8b, 0x40, 0x00, 0x00, + 0x35, 0x20, 0xd4, 0x80, 0x00, 0x00, + 0x14, 0x14, 0x50, 0x50, 0x00, 0x00, + 0xc5, 0x0b, 0x14, 0x20, 0x00, 0x00, + 0x22, 0x0c, 0x88, 0x30, 0x00, 0x00, + 0x88, 0xba, 0x22, 0xe0, 0x00, 0x00, + 0x42, 0x55, 0x09, 0x50, 0x00, 0x00, + 0x28, 0xa4, 0xa2, 0x90, 0x00, 0x00, + 0x94, 0x22, 0x50, 0x80, 0x00, 0x00, + 0x1b, 0x04, 0x6c, 0x10, 0x00, 0x00, + 0x22, 0xc0, 0x8b, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_22[132] = { + 0x62, 0xd1, 0x8b, 0x40, 0x00, 0x00, + 0x35, 0x20, 0xd4, 0x80, 0x00, 0x00, + 0x14, 0x14, 0x50, 0x50, 0x00, 0x00, + 0xc5, 0x0b, 0x14, 0x20, 0x00, 0x00, + 0x22, 0x0c, 0x88, 0x30, 0x00, 0x00, + 0x88, 0xba, 0x22, 0xe0, 0x00, 0x00, + 0x42, 0x55, 0x09, 0x50, 0x00, 0x00, + 0x28, 0xa4, 0xa2, 0x90, 0x00, 0x00, + 0x94, 0x22, 0x50, 0x80, 0x00, 0x00, + 0x1b, 0x04, 0x6c, 0x10, 0x00, 0x00, + 0x22, 0xc0, 0x8b, 0x00, 0x00, 0x00, + 0xc0, 0xd7, 0x03, 0x50, 0x00, 0x00, + 0x1d, 0x40, 0x75, 0x00, 0x00, 0x00, + 0xd4, 0x0b, 0x50, 0x20, 0x00, 0x00, + 0x02, 0x60, 0x09, 0x80, 0x00, 0x00, + 0x04, 0x28, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0x98, 0x82, 0x60, 0x00, 0x00, + 0x40, 0x45, 0x01, 0x10, 0x00, 0x00, + 0x08, 0x84, 0x22, 0x10, 0x00, 0x00, + 0x68, 0x01, 0xa0, 0x00, 0x00, 0x00, + 0x23, 0x10, 0x8c, 0x40, 0x00, 0x00, + 0x45, 0x05, 0x10, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_23[138] = { + 0x62, 0xd1, 0x8b, 0x40, 0x00, 0x00, + 0x35, 0x20, 0xd4, 0x80, 0x00, 0x00, + 0x14, 0x14, 0x50, 0x50, 0x00, 0x00, + 0xc5, 0x0b, 0x14, 0x20, 0x00, 0x00, + 0x22, 0x0c, 0x88, 0x30, 0x00, 0x00, + 0x88, 0xba, 0x22, 0xe0, 0x00, 0x00, + 0x42, 0x55, 0x09, 0x50, 0x00, 0x00, + 0x28, 0xa4, 0xa2, 0x90, 0x00, 0x00, + 0x94, 0x22, 0x50, 0x80, 0x00, 0x00, + 0x1b, 0x04, 0x6c, 0x10, 0x00, 0x00, + 0x22, 0xc0, 0x8b, 0x00, 0x00, 0x00, + 0x81, 0x06, 0x04, 0x10, 0x00, 0x00, + 0x40, 0x69, 0x01, 0xa0, 0x00, 0x00, + 0x90, 0x26, 0x40, 0x90, 0x00, 0x00, + 0x28, 0x28, 0xa0, 0xa0, 0x00, 0x00, + 0x52, 0x11, 0x48, 0x40, 0x00, 0x00, + 0x41, 0x89, 0x06, 0x20, 0x00, 0x00, + 0x09, 0x30, 0x24, 0xc0, 0x00, 0x00, + 0x48, 0x45, 0x21, 0x10, 0x00, 0x00, + 0x04, 0x44, 0x11, 0x10, 0x00, 0x00, + 0x0e, 0x80, 0x3a, 0x00, 0x00, 0x00, + 0xa5, 0x92, 0x96, 0x40, 0x00, 0x00, + 0x12, 0x0c, 0x48, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_24[144] = { + 0x81, 0x06, 0x04, 0x10, 0x00, 0x00, + 0x40, 0x69, 0x01, 0xa0, 0x00, 0x00, + 0x90, 0x26, 0x40, 0x90, 0x00, 0x00, + 0x28, 0x28, 0xa0, 0xa0, 0x00, 0x00, + 0x52, 0x11, 0x48, 0x40, 0x00, 0x00, + 0x41, 0x89, 0x06, 0x20, 0x00, 0x00, + 0x09, 0x30, 0x24, 0xc0, 0x00, 0x00, + 0x48, 0x45, 0x21, 0x10, 0x00, 0x00, + 0x04, 0x44, 0x11, 0x10, 0x00, 0x00, + 0x0e, 0x80, 0x3a, 0x00, 0x00, 0x00, + 0xa5, 0x92, 0x96, 0x40, 0x00, 0x00, + 0x12, 0x0c, 0x48, 0x30, 0x00, 0x00, + 0x62, 0xd1, 0x8b, 0x40, 0x00, 0x00, + 0x35, 0x20, 0xd4, 0x80, 0x00, 0x00, + 0x14, 0x14, 0x50, 0x50, 0x00, 0x00, + 0xc5, 0x0b, 0x14, 0x20, 0x00, 0x00, + 0x22, 0x0c, 0x88, 0x30, 0x00, 0x00, + 0x88, 0xba, 0x22, 0xe0, 0x00, 0x00, + 0x42, 0x55, 0x09, 0x50, 0x00, 0x00, + 0x28, 0xa4, 0xa2, 0x90, 0x00, 0x00, + 0x94, 0x22, 0x50, 0x80, 0x00, 0x00, + 0x1b, 0x04, 0x6c, 0x10, 0x00, 0x00, + 0x22, 0xc0, 0x8b, 0x00, 0x00, 0x00, + 0x6f, 0xd8, 0xee, 0xa0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_25[150] = { + 0x81, 0x06, 0x04, 0x10, 0x00, 0x00, + 0x40, 0x69, 0x01, 0xa0, 0x00, 0x00, + 0x90, 0x26, 0x40, 0x90, 0x00, 0x00, + 0x28, 0x28, 0xa0, 0xa0, 0x00, 0x00, + 0x52, 0x11, 0x48, 0x40, 0x00, 0x00, + 0x41, 0x89, 0x06, 0x20, 0x00, 0x00, + 0x09, 0x30, 0x24, 0xc0, 0x00, 0x00, + 0x48, 0x45, 0x21, 0x10, 0x00, 0x00, + 0x04, 0x44, 0x11, 0x10, 0x00, 0x00, + 0x0e, 0x80, 0x3a, 0x00, 0x00, 0x00, + 0xa5, 0x92, 0x96, 0x40, 0x00, 0x00, + 0x12, 0x0c, 0x48, 0x30, 0x00, 0x00, + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x48, 0x05, 0x20, 0x10, 0x00, 0x00, + 0x00, 0xac, 0x02, 0xb0, 0x00, 0x00, + 0x28, 0x08, 0xa0, 0x20, 0x00, 0x00, + 0x81, 0x0a, 0x04, 0x20, 0x00, 0x00, + 0x23, 0x04, 0x8c, 0x10, 0x00, 0x00, + 0x06, 0x80, 0x1a, 0x00, 0x00, 0x00, + 0x80, 0x16, 0x00, 0x50, 0x00, 0x00, + 0x30, 0x10, 0xc0, 0x40, 0x00, 0x00, + 0x8c, 0x22, 0x30, 0x80, 0x00, 0x00, + 0x54, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x80, 0xc2, 0x03, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_26[156] = { + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x48, 0x05, 0x20, 0x10, 0x00, 0x00, + 0x00, 0xac, 0x02, 0xb0, 0x00, 0x00, + 0x28, 0x08, 0xa0, 0x20, 0x00, 0x00, + 0x81, 0x0a, 0x04, 0x20, 0x00, 0x00, + 0x23, 0x04, 0x8c, 0x10, 0x00, 0x00, + 0x06, 0x80, 0x1a, 0x00, 0x00, 0x00, + 0x80, 0x16, 0x00, 0x50, 0x00, 0x00, + 0x30, 0x10, 0xc0, 0x40, 0x00, 0x00, + 0x8c, 0x22, 0x30, 0x80, 0x00, 0x00, + 0x54, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x80, 0xc2, 0x03, 0x00, 0x00, 0x00, + 0x81, 0x06, 0x04, 0x10, 0x00, 0x00, + 0x40, 0x69, 0x01, 0xa0, 0x00, 0x00, + 0x90, 0x26, 0x40, 0x90, 0x00, 0x00, + 0x28, 0x28, 0xa0, 0xa0, 0x00, 0x00, + 0x52, 0x11, 0x48, 0x40, 0x00, 0x00, + 0x41, 0x89, 0x06, 0x20, 0x00, 0x00, + 0x09, 0x30, 0x24, 0xc0, 0x00, 0x00, + 0x48, 0x45, 0x21, 0x10, 0x00, 0x00, + 0x04, 0x44, 0x11, 0x10, 0x00, 0x00, + 0x0e, 0x80, 0x3a, 0x00, 0x00, 0x00, + 0xa5, 0x92, 0x96, 0x40, 0x00, 0x00, + 0x12, 0x0c, 0x48, 0x30, 0x00, 0x00, + 0xf1, 0x64, 0xbe, 0x40, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_27[162] = { + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x48, 0x05, 0x20, 0x10, 0x00, 0x00, + 0x00, 0xac, 0x02, 0xb0, 0x00, 0x00, + 0x28, 0x08, 0xa0, 0x20, 0x00, 0x00, + 0x81, 0x0a, 0x04, 0x20, 0x00, 0x00, + 0x23, 0x04, 0x8c, 0x10, 0x00, 0x00, + 0x06, 0x80, 0x1a, 0x00, 0x00, 0x00, + 0x80, 0x16, 0x00, 0x50, 0x00, 0x00, + 0x30, 0x10, 0xc0, 0x40, 0x00, 0x00, + 0x8c, 0x22, 0x30, 0x80, 0x00, 0x00, + 0x54, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x80, 0xc2, 0x03, 0x00, 0x00, 0x00, + 0x40, 0x55, 0x01, 0x50, 0x00, 0x00, + 0x15, 0x40, 0x55, 0x00, 0x00, 0x00, + 0xc0, 0x07, 0x00, 0x10, 0x00, 0x00, + 0x28, 0x10, 0xa0, 0x40, 0x00, 0x00, + 0x05, 0x0c, 0x14, 0x30, 0x00, 0x00, + 0x64, 0x81, 0x92, 0x00, 0x00, 0x00, + 0x81, 0x82, 0x06, 0x00, 0x00, 0x00, + 0x10, 0x98, 0x42, 0x60, 0x00, 0x00, + 0x84, 0x22, 0x10, 0x80, 0x00, 0x00, + 0x12, 0x30, 0x48, 0xc0, 0x00, 0x00, + 0x62, 0x01, 0x88, 0x00, 0x00, 0x00, + 0x28, 0x60, 0xa1, 0x80, 0x00, 0x00, + 0x0e, 0x08, 0x38, 0x20, 0x00, 0x00, + 0x10, 0x84, 0x42, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_28[168] = { + 0x40, 0x55, 0x01, 0x50, 0x00, 0x00, + 0x15, 0x40, 0x55, 0x00, 0x00, 0x00, + 0xc0, 0x07, 0x00, 0x10, 0x00, 0x00, + 0x28, 0x10, 0xa0, 0x40, 0x00, 0x00, + 0x05, 0x0c, 0x14, 0x30, 0x00, 0x00, + 0x64, 0x81, 0x92, 0x00, 0x00, 0x00, + 0x81, 0x82, 0x06, 0x00, 0x00, 0x00, + 0x10, 0x98, 0x42, 0x60, 0x00, 0x00, + 0x84, 0x22, 0x10, 0x80, 0x00, 0x00, + 0x12, 0x30, 0x48, 0xc0, 0x00, 0x00, + 0x62, 0x01, 0x88, 0x00, 0x00, 0x00, + 0x28, 0x60, 0xa1, 0x80, 0x00, 0x00, + 0x0e, 0x08, 0x38, 0x20, 0x00, 0x00, + 0x10, 0x84, 0x42, 0x10, 0x00, 0x00, + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x48, 0x05, 0x20, 0x10, 0x00, 0x00, + 0x00, 0xac, 0x02, 0xb0, 0x00, 0x00, + 0x28, 0x08, 0xa0, 0x20, 0x00, 0x00, + 0x81, 0x0a, 0x04, 0x20, 0x00, 0x00, + 0x23, 0x04, 0x8c, 0x10, 0x00, 0x00, + 0x06, 0x80, 0x1a, 0x00, 0x00, 0x00, + 0x80, 0x16, 0x00, 0x50, 0x00, 0x00, + 0x30, 0x10, 0xc0, 0x40, 0x00, 0x00, + 0x8c, 0x22, 0x30, 0x80, 0x00, 0x00, + 0x54, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x80, 0xc2, 0x03, 0x00, 0x00, 0x00, + 0x36, 0x4f, 0x1f, 0xb0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_3[18] = { + 0xac, 0xda, 0xb3, 0x60, 0x00, 0x00, + 0x55, 0x6d, 0x55, 0xb0, 0x00, 0x00, + 0x27, 0xb4, 0x9e, 0xd0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_4[24] = { + 0x2c, 0xd8, 0xb3, 0x60, 0x00, 0x00, + 0x93, 0x6a, 0x4d, 0xa0, 0x00, 0x00, + 0x1a, 0xb4, 0x6a, 0xd0, 0x00, 0x00, + 0x47, 0x2d, 0x1c, 0xb0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_5[30] = { + 0x64, 0xd9, 0x93, 0x60, 0x00, 0x00, + 0xa5, 0x6a, 0x95, 0xa0, 0x00, 0x00, + 0x52, 0xb5, 0x4a, 0xd0, 0x00, 0x00, + 0x1d, 0xa8, 0x76, 0xa0, 0x00, 0x00, + 0x9c, 0x56, 0x71, 0x50, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_6[36] = { + 0x4a, 0x55, 0x29, 0x50, 0x00, 0x00, + 0x95, 0x4a, 0x55, 0x20, 0x00, 0x00, + 0x14, 0xb4, 0x52, 0xd0, 0x00, 0x00, + 0x51, 0xa9, 0x46, 0xa0, 0x00, 0x00, + 0x22, 0x6c, 0x89, 0xb0, 0x00, 0x00, + 0x88, 0x8e, 0x22, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_7[42] = { + 0x62, 0x55, 0x89, 0x50, 0x00, 0x00, + 0xb9, 0x22, 0xe4, 0x80, 0x00, 0x00, + 0x18, 0xb4, 0x62, 0xd0, 0x00, 0x00, + 0x54, 0x99, 0x52, 0x60, 0x00, 0x00, + 0x06, 0x6c, 0x19, 0xb0, 0x00, 0x00, + 0x85, 0x56, 0x15, 0x50, 0x00, 0x00, + 0xaa, 0x8a, 0xaa, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_8[48] = { + 0xc0, 0x17, 0x00, 0x50, 0x00, 0x00, + 0x41, 0x61, 0x05, 0x80, 0x00, 0x00, + 0x88, 0x32, 0x20, 0xc0, 0x00, 0x00, + 0x20, 0xa4, 0x82, 0x90, 0x00, 0x00, + 0x0a, 0x48, 0x29, 0x20, 0x00, 0x00, + 0x04, 0x98, 0x12, 0x60, 0x00, 0x00, + 0x94, 0x42, 0x51, 0x00, 0x00, 0x00, + 0x72, 0x01, 0xc8, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom28_9[54] = { + 0xa2, 0x56, 0x89, 0x50, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x80, 0x00, 0x00, + 0x4a, 0x25, 0x28, 0x90, 0x00, 0x00, + 0x20, 0xa8, 0x82, 0xa0, 0x00, 0x00, + 0x11, 0x84, 0x46, 0x10, 0x00, 0x00, + 0x49, 0x09, 0x24, 0x20, 0x00, 0x00, + 0x86, 0x0e, 0x18, 0x30, 0x00, 0x00, + 0x20, 0xd4, 0x83, 0x50, 0x00, 0x00, + 0x88, 0x4a, 0x21, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_1[6] = { + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_10[60] = { + 0xc0, 0xd7, 0x02, 0x80, 0x00, 0x00, + 0x1d, 0x40, 0x55, 0x58, 0x00, 0x00, + 0xd4, 0x09, 0xd1, 0x00, 0x00, 0x00, + 0x02, 0x60, 0x02, 0x70, 0x00, 0x00, + 0x04, 0x28, 0x04, 0xb0, 0x00, 0x00, + 0x20, 0x99, 0x12, 0x48, 0x00, 0x00, + 0x40, 0x46, 0x21, 0x40, 0x00, 0x00, + 0x08, 0x84, 0x82, 0x90, 0x00, 0x00, + 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, + 0x23, 0x10, 0x09, 0x88, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_11[66] = { + 0x62, 0xd1, 0x88, 0x88, 0x00, 0x00, + 0x35, 0x23, 0xc4, 0x40, 0x00, 0x00, + 0x14, 0x14, 0x40, 0x38, 0x00, 0x00, + 0xc5, 0x08, 0x42, 0xc0, 0x00, 0x00, + 0x22, 0x0c, 0x90, 0x90, 0x00, 0x00, + 0x88, 0xb8, 0x04, 0x48, 0x00, 0x00, + 0x42, 0x54, 0x03, 0x10, 0x00, 0x00, + 0x28, 0xa4, 0x12, 0x88, 0x00, 0x00, + 0x94, 0x20, 0x09, 0x60, 0x00, 0x00, + 0x1b, 0x04, 0xac, 0x00, 0x00, 0x00, + 0x22, 0xc2, 0x61, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_12[72] = { + 0x81, 0x06, 0x22, 0x40, 0x00, 0x00, + 0x40, 0x69, 0x01, 0x50, 0x00, 0x00, + 0x90, 0x26, 0x09, 0x88, 0x00, 0x00, + 0x28, 0x28, 0x86, 0x90, 0x00, 0x00, + 0x52, 0x10, 0x41, 0x90, 0x00, 0x00, + 0x41, 0x89, 0x10, 0x28, 0x00, 0x00, + 0x09, 0x30, 0x43, 0x20, 0x00, 0x00, + 0x48, 0x45, 0x34, 0xa8, 0x00, 0x00, + 0x04, 0x44, 0xe0, 0x08, 0x00, 0x00, + 0x0e, 0x80, 0x5d, 0x20, 0x00, 0x00, + 0xa5, 0x92, 0x42, 0x10, 0x00, 0x00, + 0x12, 0x0d, 0xc8, 0x50, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_13[78] = { + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x10, 0x00, 0x00, + 0x48, 0x05, 0x01, 0x28, 0x00, 0x00, + 0x00, 0xaf, 0x10, 0x10, 0x00, 0x00, + 0x28, 0x08, 0x21, 0x80, 0x00, 0x00, + 0x81, 0x0a, 0x50, 0x48, 0x00, 0x00, + 0x23, 0x06, 0x23, 0x00, 0x00, 0x00, + 0x06, 0x80, 0x84, 0xc8, 0x00, 0x00, + 0x80, 0x17, 0x05, 0x00, 0x00, 0x00, + 0x30, 0x10, 0x41, 0xa0, 0x00, 0x00, + 0x8c, 0x20, 0x1a, 0x40, 0x00, 0x00, + 0x54, 0x01, 0x64, 0x00, 0x00, 0x00, + 0x80, 0xc0, 0x28, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_14[84] = { + 0x40, 0x55, 0x02, 0x08, 0x00, 0x00, + 0x15, 0x40, 0x55, 0x50, 0x00, 0x00, + 0xc0, 0x06, 0x20, 0x48, 0x00, 0x00, + 0x28, 0x13, 0x00, 0x40, 0x00, 0x00, + 0x05, 0x0e, 0x02, 0x80, 0x00, 0x00, + 0x64, 0x80, 0x04, 0x88, 0x00, 0x00, + 0x81, 0x81, 0x00, 0xb0, 0x00, 0x00, + 0x10, 0x98, 0x88, 0x08, 0x00, 0x00, + 0x84, 0x22, 0x40, 0x10, 0x00, 0x00, + 0x12, 0x30, 0x49, 0x00, 0x00, 0x00, + 0x62, 0x01, 0x74, 0x00, 0x00, 0x00, + 0x28, 0x60, 0x81, 0x50, 0x00, 0x00, + 0x0e, 0x0a, 0x18, 0x20, 0x00, 0x00, + 0x10, 0x84, 0xa2, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_15[90] = { + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0xb9, 0x22, 0xc4, 0x50, 0x00, 0x00, + 0x18, 0xb4, 0x61, 0xa8, 0x00, 0x00, + 0x54, 0x99, 0x13, 0x50, 0x00, 0x00, + 0x06, 0x6c, 0x4d, 0x90, 0x00, 0x00, + 0x85, 0x55, 0x24, 0x68, 0x00, 0x00, + 0xaa, 0x8a, 0x1a, 0x30, 0x00, 0x00, + 0xc0, 0x16, 0x40, 0x88, 0x00, 0x00, + 0x41, 0x60, 0x25, 0x40, 0x00, 0x00, + 0x88, 0x30, 0x01, 0xa8, 0x00, 0x00, + 0x20, 0xa4, 0x80, 0xd0, 0x00, 0x00, + 0x0a, 0x48, 0x51, 0x10, 0x00, 0x00, + 0x04, 0x9b, 0x08, 0x40, 0x00, 0x00, + 0x94, 0x40, 0x03, 0x18, 0x00, 0x00, + 0x72, 0x01, 0x96, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_16[96] = { + 0xc0, 0x16, 0x40, 0x88, 0x00, 0x00, + 0x41, 0x60, 0x25, 0x40, 0x00, 0x00, + 0x88, 0x30, 0x01, 0xa8, 0x00, 0x00, + 0x20, 0xa4, 0x80, 0xd0, 0x00, 0x00, + 0x0a, 0x48, 0x51, 0x10, 0x00, 0x00, + 0x04, 0x9b, 0x08, 0x40, 0x00, 0x00, + 0x94, 0x40, 0x03, 0x18, 0x00, 0x00, + 0x72, 0x01, 0x96, 0x00, 0x00, 0x00, + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0xb9, 0x22, 0xc4, 0x50, 0x00, 0x00, + 0x18, 0xb4, 0x61, 0xa8, 0x00, 0x00, + 0x54, 0x99, 0x13, 0x50, 0x00, 0x00, + 0x06, 0x6c, 0x4d, 0x90, 0x00, 0x00, + 0x85, 0x55, 0x24, 0x68, 0x00, 0x00, + 0xaa, 0x8a, 0x1a, 0x30, 0x00, 0x00, + 0x0d, 0x2c, 0xf2, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_17[102] = { + 0xc0, 0x16, 0x40, 0x88, 0x00, 0x00, + 0x41, 0x60, 0x25, 0x40, 0x00, 0x00, + 0x88, 0x30, 0x01, 0xa8, 0x00, 0x00, + 0x20, 0xa4, 0x80, 0xd0, 0x00, 0x00, + 0x0a, 0x48, 0x51, 0x10, 0x00, 0x00, + 0x04, 0x9b, 0x08, 0x40, 0x00, 0x00, + 0x94, 0x40, 0x03, 0x18, 0x00, 0x00, + 0x72, 0x01, 0x96, 0x00, 0x00, 0x00, + 0xa2, 0x55, 0x88, 0x88, 0x00, 0x00, + 0x34, 0x60, 0x91, 0x10, 0x00, 0x00, + 0x4a, 0x27, 0x01, 0x40, 0x00, 0x00, + 0x20, 0xa8, 0x0c, 0x30, 0x00, 0x00, + 0x11, 0x84, 0x58, 0xa0, 0x00, 0x00, + 0x49, 0x0a, 0x24, 0x00, 0x00, 0x00, + 0x86, 0x0e, 0x0a, 0x40, 0x00, 0x00, + 0x20, 0xd4, 0x22, 0x90, 0x00, 0x00, + 0x88, 0x4a, 0x41, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_18[108] = { + 0xa2, 0x55, 0x88, 0x88, 0x00, 0x00, + 0x34, 0x60, 0x91, 0x10, 0x00, 0x00, + 0x4a, 0x27, 0x01, 0x40, 0x00, 0x00, + 0x20, 0xa8, 0x0c, 0x30, 0x00, 0x00, + 0x11, 0x84, 0x58, 0xa0, 0x00, 0x00, + 0x49, 0x0a, 0x24, 0x00, 0x00, 0x00, + 0x86, 0x0e, 0x0a, 0x40, 0x00, 0x00, + 0x20, 0xd4, 0x22, 0x90, 0x00, 0x00, + 0x88, 0x4a, 0x41, 0x20, 0x00, 0x00, + 0xc0, 0x16, 0x40, 0x88, 0x00, 0x00, + 0x41, 0x60, 0x25, 0x40, 0x00, 0x00, + 0x88, 0x30, 0x01, 0xa8, 0x00, 0x00, + 0x20, 0xa4, 0x80, 0xd0, 0x00, 0x00, + 0x0a, 0x48, 0x51, 0x10, 0x00, 0x00, + 0x04, 0x9b, 0x08, 0x40, 0x00, 0x00, + 0x94, 0x40, 0x03, 0x18, 0x00, 0x00, + 0x72, 0x01, 0x96, 0x00, 0x00, 0x00, + 0x71, 0x36, 0xf2, 0xb0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_19[114] = { + 0xa2, 0x55, 0x88, 0x88, 0x00, 0x00, + 0x34, 0x60, 0x91, 0x10, 0x00, 0x00, + 0x4a, 0x27, 0x01, 0x40, 0x00, 0x00, + 0x20, 0xa8, 0x0c, 0x30, 0x00, 0x00, + 0x11, 0x84, 0x58, 0xa0, 0x00, 0x00, + 0x49, 0x0a, 0x24, 0x00, 0x00, 0x00, + 0x86, 0x0e, 0x0a, 0x40, 0x00, 0x00, + 0x20, 0xd4, 0x22, 0x90, 0x00, 0x00, + 0x88, 0x4a, 0x41, 0x20, 0x00, 0x00, + 0xc0, 0xd7, 0x02, 0x80, 0x00, 0x00, + 0x1d, 0x40, 0x55, 0x58, 0x00, 0x00, + 0xd4, 0x09, 0xd1, 0x00, 0x00, 0x00, + 0x02, 0x60, 0x02, 0x70, 0x00, 0x00, + 0x04, 0x28, 0x04, 0xb0, 0x00, 0x00, + 0x20, 0x99, 0x12, 0x48, 0x00, 0x00, + 0x40, 0x46, 0x21, 0x40, 0x00, 0x00, + 0x08, 0x84, 0x82, 0x90, 0x00, 0x00, + 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, + 0x23, 0x10, 0x09, 0x88, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_2[12] = { + 0xec, 0xeb, 0xb3, 0xa8, 0x00, 0x00, + 0x3b, 0x9e, 0xee, 0x70, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_20[120] = { + 0xc0, 0xd7, 0x02, 0x80, 0x00, 0x00, + 0x1d, 0x40, 0x55, 0x58, 0x00, 0x00, + 0xd4, 0x09, 0xd1, 0x00, 0x00, 0x00, + 0x02, 0x60, 0x02, 0x70, 0x00, 0x00, + 0x04, 0x28, 0x04, 0xb0, 0x00, 0x00, + 0x20, 0x99, 0x12, 0x48, 0x00, 0x00, + 0x40, 0x46, 0x21, 0x40, 0x00, 0x00, + 0x08, 0x84, 0x82, 0x90, 0x00, 0x00, + 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, + 0x23, 0x10, 0x09, 0x88, 0x00, 0x00, + 0xa2, 0x55, 0x88, 0x88, 0x00, 0x00, + 0x34, 0x60, 0x91, 0x10, 0x00, 0x00, + 0x4a, 0x27, 0x01, 0x40, 0x00, 0x00, + 0x20, 0xa8, 0x0c, 0x30, 0x00, 0x00, + 0x11, 0x84, 0x58, 0xa0, 0x00, 0x00, + 0x49, 0x0a, 0x24, 0x00, 0x00, 0x00, + 0x86, 0x0e, 0x0a, 0x40, 0x00, 0x00, + 0x20, 0xd4, 0x22, 0x90, 0x00, 0x00, + 0x88, 0x4a, 0x41, 0x20, 0x00, 0x00, + 0xe7, 0xec, 0xdc, 0xb0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_21[126] = { + 0xc0, 0xd7, 0x02, 0x80, 0x00, 0x00, + 0x1d, 0x40, 0x55, 0x58, 0x00, 0x00, + 0xd4, 0x09, 0xd1, 0x00, 0x00, 0x00, + 0x02, 0x60, 0x02, 0x70, 0x00, 0x00, + 0x04, 0x28, 0x04, 0xb0, 0x00, 0x00, + 0x20, 0x99, 0x12, 0x48, 0x00, 0x00, + 0x40, 0x46, 0x21, 0x40, 0x00, 0x00, + 0x08, 0x84, 0x82, 0x90, 0x00, 0x00, + 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, + 0x23, 0x10, 0x09, 0x88, 0x00, 0x00, + 0x62, 0xd1, 0x88, 0x88, 0x00, 0x00, + 0x35, 0x23, 0xc4, 0x40, 0x00, 0x00, + 0x14, 0x14, 0x40, 0x38, 0x00, 0x00, + 0xc5, 0x08, 0x42, 0xc0, 0x00, 0x00, + 0x22, 0x0c, 0x90, 0x90, 0x00, 0x00, + 0x88, 0xb8, 0x04, 0x48, 0x00, 0x00, + 0x42, 0x54, 0x03, 0x10, 0x00, 0x00, + 0x28, 0xa4, 0x12, 0x88, 0x00, 0x00, + 0x94, 0x20, 0x09, 0x60, 0x00, 0x00, + 0x1b, 0x04, 0xac, 0x00, 0x00, 0x00, + 0x22, 0xc2, 0x61, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_22[132] = { + 0x62, 0xd1, 0x88, 0x88, 0x00, 0x00, + 0x35, 0x23, 0xc4, 0x40, 0x00, 0x00, + 0x14, 0x14, 0x40, 0x38, 0x00, 0x00, + 0xc5, 0x08, 0x42, 0xc0, 0x00, 0x00, + 0x22, 0x0c, 0x90, 0x90, 0x00, 0x00, + 0x88, 0xb8, 0x04, 0x48, 0x00, 0x00, + 0x42, 0x54, 0x03, 0x10, 0x00, 0x00, + 0x28, 0xa4, 0x12, 0x88, 0x00, 0x00, + 0x94, 0x20, 0x09, 0x60, 0x00, 0x00, + 0x1b, 0x04, 0xac, 0x00, 0x00, 0x00, + 0x22, 0xc2, 0x61, 0x00, 0x00, 0x00, + 0xc0, 0xd7, 0x02, 0x80, 0x00, 0x00, + 0x1d, 0x40, 0x55, 0x58, 0x00, 0x00, + 0xd4, 0x09, 0xd1, 0x00, 0x00, 0x00, + 0x02, 0x60, 0x02, 0x70, 0x00, 0x00, + 0x04, 0x28, 0x04, 0xb0, 0x00, 0x00, + 0x20, 0x99, 0x12, 0x48, 0x00, 0x00, + 0x40, 0x46, 0x21, 0x40, 0x00, 0x00, + 0x08, 0x84, 0x82, 0x90, 0x00, 0x00, + 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, + 0x23, 0x10, 0x09, 0x88, 0x00, 0x00, + 0x1c, 0x90, 0xa9, 0xa0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_23[138] = { + 0x62, 0xd1, 0x88, 0x88, 0x00, 0x00, + 0x35, 0x23, 0xc4, 0x40, 0x00, 0x00, + 0x14, 0x14, 0x40, 0x38, 0x00, 0x00, + 0xc5, 0x08, 0x42, 0xc0, 0x00, 0x00, + 0x22, 0x0c, 0x90, 0x90, 0x00, 0x00, + 0x88, 0xb8, 0x04, 0x48, 0x00, 0x00, + 0x42, 0x54, 0x03, 0x10, 0x00, 0x00, + 0x28, 0xa4, 0x12, 0x88, 0x00, 0x00, + 0x94, 0x20, 0x09, 0x60, 0x00, 0x00, + 0x1b, 0x04, 0xac, 0x00, 0x00, 0x00, + 0x22, 0xc2, 0x61, 0x00, 0x00, 0x00, + 0x81, 0x06, 0x22, 0x40, 0x00, 0x00, + 0x40, 0x69, 0x01, 0x50, 0x00, 0x00, + 0x90, 0x26, 0x09, 0x88, 0x00, 0x00, + 0x28, 0x28, 0x86, 0x90, 0x00, 0x00, + 0x52, 0x10, 0x41, 0x90, 0x00, 0x00, + 0x41, 0x89, 0x10, 0x28, 0x00, 0x00, + 0x09, 0x30, 0x43, 0x20, 0x00, 0x00, + 0x48, 0x45, 0x34, 0xa8, 0x00, 0x00, + 0x04, 0x44, 0xe0, 0x08, 0x00, 0x00, + 0x0e, 0x80, 0x5d, 0x20, 0x00, 0x00, + 0xa5, 0x92, 0x42, 0x10, 0x00, 0x00, + 0x12, 0x0d, 0xc8, 0x50, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_24[144] = { + 0x81, 0x06, 0x22, 0x40, 0x00, 0x00, + 0x40, 0x69, 0x01, 0x50, 0x00, 0x00, + 0x90, 0x26, 0x09, 0x88, 0x00, 0x00, + 0x28, 0x28, 0x86, 0x90, 0x00, 0x00, + 0x52, 0x10, 0x41, 0x90, 0x00, 0x00, + 0x41, 0x89, 0x10, 0x28, 0x00, 0x00, + 0x09, 0x30, 0x43, 0x20, 0x00, 0x00, + 0x48, 0x45, 0x34, 0xa8, 0x00, 0x00, + 0x04, 0x44, 0xe0, 0x08, 0x00, 0x00, + 0x0e, 0x80, 0x5d, 0x20, 0x00, 0x00, + 0xa5, 0x92, 0x42, 0x10, 0x00, 0x00, + 0x12, 0x0d, 0xc8, 0x50, 0x00, 0x00, + 0x62, 0xd1, 0x88, 0x88, 0x00, 0x00, + 0x35, 0x23, 0xc4, 0x40, 0x00, 0x00, + 0x14, 0x14, 0x40, 0x38, 0x00, 0x00, + 0xc5, 0x08, 0x42, 0xc0, 0x00, 0x00, + 0x22, 0x0c, 0x90, 0x90, 0x00, 0x00, + 0x88, 0xb8, 0x04, 0x48, 0x00, 0x00, + 0x42, 0x54, 0x03, 0x10, 0x00, 0x00, + 0x28, 0xa4, 0x12, 0x88, 0x00, 0x00, + 0x94, 0x20, 0x09, 0x60, 0x00, 0x00, + 0x1b, 0x04, 0xac, 0x00, 0x00, 0x00, + 0x22, 0xc2, 0x61, 0x00, 0x00, 0x00, + 0xbd, 0x86, 0x97, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_25[150] = { + 0x81, 0x06, 0x22, 0x40, 0x00, 0x00, + 0x40, 0x69, 0x01, 0x50, 0x00, 0x00, + 0x90, 0x26, 0x09, 0x88, 0x00, 0x00, + 0x28, 0x28, 0x86, 0x90, 0x00, 0x00, + 0x52, 0x10, 0x41, 0x90, 0x00, 0x00, + 0x41, 0x89, 0x10, 0x28, 0x00, 0x00, + 0x09, 0x30, 0x43, 0x20, 0x00, 0x00, + 0x48, 0x45, 0x34, 0xa8, 0x00, 0x00, + 0x04, 0x44, 0xe0, 0x08, 0x00, 0x00, + 0x0e, 0x80, 0x5d, 0x20, 0x00, 0x00, + 0xa5, 0x92, 0x42, 0x10, 0x00, 0x00, + 0x12, 0x0d, 0xc8, 0x50, 0x00, 0x00, + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x10, 0x00, 0x00, + 0x48, 0x05, 0x01, 0x28, 0x00, 0x00, + 0x00, 0xaf, 0x10, 0x10, 0x00, 0x00, + 0x28, 0x08, 0x21, 0x80, 0x00, 0x00, + 0x81, 0x0a, 0x50, 0x48, 0x00, 0x00, + 0x23, 0x06, 0x23, 0x00, 0x00, 0x00, + 0x06, 0x80, 0x84, 0xc8, 0x00, 0x00, + 0x80, 0x17, 0x05, 0x00, 0x00, 0x00, + 0x30, 0x10, 0x41, 0xa0, 0x00, 0x00, + 0x8c, 0x20, 0x1a, 0x40, 0x00, 0x00, + 0x54, 0x01, 0x64, 0x00, 0x00, 0x00, + 0x80, 0xc0, 0x28, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_26[156] = { + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x10, 0x00, 0x00, + 0x48, 0x05, 0x01, 0x28, 0x00, 0x00, + 0x00, 0xaf, 0x10, 0x10, 0x00, 0x00, + 0x28, 0x08, 0x21, 0x80, 0x00, 0x00, + 0x81, 0x0a, 0x50, 0x48, 0x00, 0x00, + 0x23, 0x06, 0x23, 0x00, 0x00, 0x00, + 0x06, 0x80, 0x84, 0xc8, 0x00, 0x00, + 0x80, 0x17, 0x05, 0x00, 0x00, 0x00, + 0x30, 0x10, 0x41, 0xa0, 0x00, 0x00, + 0x8c, 0x20, 0x1a, 0x40, 0x00, 0x00, + 0x54, 0x01, 0x64, 0x00, 0x00, 0x00, + 0x80, 0xc0, 0x28, 0x30, 0x00, 0x00, + 0x81, 0x06, 0x22, 0x40, 0x00, 0x00, + 0x40, 0x69, 0x01, 0x50, 0x00, 0x00, + 0x90, 0x26, 0x09, 0x88, 0x00, 0x00, + 0x28, 0x28, 0x86, 0x90, 0x00, 0x00, + 0x52, 0x10, 0x41, 0x90, 0x00, 0x00, + 0x41, 0x89, 0x10, 0x28, 0x00, 0x00, + 0x09, 0x30, 0x43, 0x20, 0x00, 0x00, + 0x48, 0x45, 0x34, 0xa8, 0x00, 0x00, + 0x04, 0x44, 0xe0, 0x08, 0x00, 0x00, + 0x0e, 0x80, 0x5d, 0x20, 0x00, 0x00, + 0xa5, 0x92, 0x42, 0x10, 0x00, 0x00, + 0x12, 0x0d, 0xc8, 0x50, 0x00, 0x00, + 0xb5, 0x4c, 0xa9, 0x70, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_27[162] = { + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x10, 0x00, 0x00, + 0x48, 0x05, 0x01, 0x28, 0x00, 0x00, + 0x00, 0xaf, 0x10, 0x10, 0x00, 0x00, + 0x28, 0x08, 0x21, 0x80, 0x00, 0x00, + 0x81, 0x0a, 0x50, 0x48, 0x00, 0x00, + 0x23, 0x06, 0x23, 0x00, 0x00, 0x00, + 0x06, 0x80, 0x84, 0xc8, 0x00, 0x00, + 0x80, 0x17, 0x05, 0x00, 0x00, 0x00, + 0x30, 0x10, 0x41, 0xa0, 0x00, 0x00, + 0x8c, 0x20, 0x1a, 0x40, 0x00, 0x00, + 0x54, 0x01, 0x64, 0x00, 0x00, 0x00, + 0x80, 0xc0, 0x28, 0x30, 0x00, 0x00, + 0x40, 0x55, 0x02, 0x08, 0x00, 0x00, + 0x15, 0x40, 0x55, 0x50, 0x00, 0x00, + 0xc0, 0x06, 0x20, 0x48, 0x00, 0x00, + 0x28, 0x13, 0x00, 0x40, 0x00, 0x00, + 0x05, 0x0e, 0x02, 0x80, 0x00, 0x00, + 0x64, 0x80, 0x04, 0x88, 0x00, 0x00, + 0x81, 0x81, 0x00, 0xb0, 0x00, 0x00, + 0x10, 0x98, 0x88, 0x08, 0x00, 0x00, + 0x84, 0x22, 0x40, 0x10, 0x00, 0x00, + 0x12, 0x30, 0x49, 0x00, 0x00, 0x00, + 0x62, 0x01, 0x74, 0x00, 0x00, 0x00, + 0x28, 0x60, 0x81, 0x50, 0x00, 0x00, + 0x0e, 0x0a, 0x18, 0x20, 0x00, 0x00, + 0x10, 0x84, 0xa2, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_28[168] = { + 0x40, 0x55, 0x02, 0x08, 0x00, 0x00, + 0x15, 0x40, 0x55, 0x50, 0x00, 0x00, + 0xc0, 0x06, 0x20, 0x48, 0x00, 0x00, + 0x28, 0x13, 0x00, 0x40, 0x00, 0x00, + 0x05, 0x0e, 0x02, 0x80, 0x00, 0x00, + 0x64, 0x80, 0x04, 0x88, 0x00, 0x00, + 0x81, 0x81, 0x00, 0xb0, 0x00, 0x00, + 0x10, 0x98, 0x88, 0x08, 0x00, 0x00, + 0x84, 0x22, 0x40, 0x10, 0x00, 0x00, + 0x12, 0x30, 0x49, 0x00, 0x00, 0x00, + 0x62, 0x01, 0x74, 0x00, 0x00, 0x00, + 0x28, 0x60, 0x81, 0x50, 0x00, 0x00, + 0x0e, 0x0a, 0x18, 0x20, 0x00, 0x00, + 0x10, 0x84, 0xa2, 0x20, 0x00, 0x00, + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0x34, 0x60, 0xd1, 0x10, 0x00, 0x00, + 0x48, 0x05, 0x01, 0x28, 0x00, 0x00, + 0x00, 0xaf, 0x10, 0x10, 0x00, 0x00, + 0x28, 0x08, 0x21, 0x80, 0x00, 0x00, + 0x81, 0x0a, 0x50, 0x48, 0x00, 0x00, + 0x23, 0x06, 0x23, 0x00, 0x00, 0x00, + 0x06, 0x80, 0x84, 0xc8, 0x00, 0x00, + 0x80, 0x17, 0x05, 0x00, 0x00, 0x00, + 0x30, 0x10, 0x41, 0xa0, 0x00, 0x00, + 0x8c, 0x20, 0x1a, 0x40, 0x00, 0x00, + 0x54, 0x01, 0x64, 0x00, 0x00, 0x00, + 0x80, 0xc0, 0x28, 0x30, 0x00, 0x00, + 0xbe, 0x1f, 0x99, 0xb0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_29[174] = { + 0x40, 0x55, 0x02, 0x08, 0x00, 0x00, + 0x15, 0x40, 0x55, 0x50, 0x00, 0x00, + 0xc0, 0x06, 0x20, 0x48, 0x00, 0x00, + 0x28, 0x13, 0x00, 0x40, 0x00, 0x00, + 0x05, 0x0e, 0x02, 0x80, 0x00, 0x00, + 0x64, 0x80, 0x04, 0x88, 0x00, 0x00, + 0x81, 0x81, 0x00, 0xb0, 0x00, 0x00, + 0x10, 0x98, 0x88, 0x08, 0x00, 0x00, + 0x84, 0x22, 0x40, 0x10, 0x00, 0x00, + 0x12, 0x30, 0x49, 0x00, 0x00, 0x00, + 0x62, 0x01, 0x74, 0x00, 0x00, 0x00, + 0x28, 0x60, 0x81, 0x50, 0x00, 0x00, + 0x0e, 0x0a, 0x18, 0x20, 0x00, 0x00, + 0x10, 0x84, 0xa2, 0x20, 0x00, 0x00, + 0x40, 0x55, 0x88, 0x88, 0x00, 0x00, + 0x15, 0x40, 0xc4, 0x40, 0x00, 0x00, + 0xc0, 0x05, 0x60, 0x00, 0x00, 0x00, + 0x28, 0x10, 0x04, 0x48, 0x00, 0x00, + 0x05, 0x0e, 0x20, 0x80, 0x00, 0x00, + 0x64, 0x81, 0x10, 0x08, 0x00, 0x00, + 0x81, 0x80, 0xa4, 0x10, 0x00, 0x00, + 0x10, 0x9a, 0x0a, 0x80, 0x00, 0x00, + 0x84, 0x20, 0x28, 0x68, 0x00, 0x00, + 0x12, 0x30, 0x47, 0x80, 0x00, 0x00, + 0x62, 0x02, 0x10, 0x10, 0x00, 0x00, + 0x28, 0x62, 0x19, 0x00, 0x00, 0x00, + 0x0e, 0x08, 0x02, 0x18, 0x00, 0x00, + 0x10, 0x85, 0x11, 0x20, 0x00, 0x00, + 0x29, 0x50, 0x42, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_3[18] = { + 0xac, 0xda, 0xb2, 0x48, 0x00, 0x00, + 0x55, 0x6d, 0x55, 0x28, 0x00, 0x00, + 0x27, 0xb5, 0x0c, 0xd8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_4[24] = { + 0x2c, 0xd8, 0x96, 0xa8, 0x00, 0x00, + 0x93, 0x6a, 0x55, 0x50, 0x00, 0x00, + 0x1a, 0xb4, 0x69, 0xa8, 0x00, 0x00, + 0x47, 0x2d, 0x0f, 0x50, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_5[30] = { + 0x64, 0xd9, 0x92, 0x88, 0x00, 0x00, + 0xa5, 0x68, 0x95, 0x50, 0x00, 0x00, + 0x52, 0xb5, 0x25, 0xa0, 0x00, 0x00, + 0x1d, 0xa9, 0x4e, 0x40, 0x00, 0x00, + 0x9c, 0x56, 0x38, 0xc0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_6[36] = { + 0x4a, 0x55, 0x8a, 0x28, 0x00, 0x00, + 0x95, 0x48, 0x55, 0x50, 0x00, 0x00, + 0x14, 0xb5, 0x31, 0x18, 0x00, 0x00, + 0x51, 0xa9, 0x4a, 0x50, 0x00, 0x00, + 0x22, 0x6c, 0x8d, 0x90, 0x00, 0x00, + 0x88, 0x8e, 0x29, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_7[42] = { + 0x62, 0x55, 0x8a, 0x88, 0x00, 0x00, + 0xb9, 0x22, 0xc4, 0x50, 0x00, 0x00, + 0x18, 0xb4, 0x61, 0xa8, 0x00, 0x00, + 0x54, 0x99, 0x13, 0x50, 0x00, 0x00, + 0x06, 0x6c, 0x4d, 0x90, 0x00, 0x00, + 0x85, 0x55, 0x24, 0x68, 0x00, 0x00, + 0xaa, 0x8a, 0x1a, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_8[48] = { + 0xc0, 0x16, 0x40, 0x88, 0x00, 0x00, + 0x41, 0x60, 0x25, 0x40, 0x00, 0x00, + 0x88, 0x30, 0x01, 0xa8, 0x00, 0x00, + 0x20, 0xa4, 0x80, 0xd0, 0x00, 0x00, + 0x0a, 0x48, 0x51, 0x10, 0x00, 0x00, + 0x04, 0x9b, 0x08, 0x40, 0x00, 0x00, + 0x94, 0x40, 0x03, 0x18, 0x00, 0x00, + 0x72, 0x01, 0x96, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom29_9[54] = { + 0xa2, 0x55, 0x88, 0x88, 0x00, 0x00, + 0x34, 0x60, 0x91, 0x10, 0x00, 0x00, + 0x4a, 0x27, 0x01, 0x40, 0x00, 0x00, + 0x20, 0xa8, 0x0c, 0x30, 0x00, 0x00, + 0x11, 0x84, 0x58, 0xa0, 0x00, 0x00, + 0x49, 0x0a, 0x24, 0x00, 0x00, 0x00, + 0x86, 0x0e, 0x0a, 0x40, 0x00, 0x00, + 0x20, 0xd4, 0x22, 0x90, 0x00, 0x00, + 0x88, 0x4a, 0x41, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom2_1[2] = { + 0xc0, 0x00 +}; + +const uint8_t kMaskRandom2_2[4] = { + 0xc0, 0x00, + 0x80, 0x00 +}; + +const uint8_t kMaskRandom30_1[6] = { + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_10[60] = { + 0xc0, 0xa1, 0x81, 0x40, 0x00, 0x00, + 0x15, 0x56, 0x2a, 0xac, 0x00, 0x00, + 0x74, 0x40, 0xe8, 0x80, 0x00, 0x00, + 0x00, 0x9c, 0x01, 0x38, 0x00, 0x00, + 0x01, 0x2c, 0x02, 0x58, 0x00, 0x00, + 0x44, 0x92, 0x89, 0x24, 0x00, 0x00, + 0x88, 0x51, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0xa4, 0x41, 0x48, 0x00, 0x00, + 0xaa, 0x05, 0x54, 0x08, 0x00, 0x00, + 0x02, 0x62, 0x04, 0xc4, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_11[66] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0xf1, 0x11, 0xe2, 0x20, 0x00, 0x00, + 0x10, 0x0e, 0x20, 0x1c, 0x00, 0x00, + 0x10, 0xb0, 0x21, 0x60, 0x00, 0x00, + 0x24, 0x24, 0x48, 0x48, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x00, 0xc4, 0x01, 0x88, 0x00, 0x00, + 0x04, 0xa2, 0x09, 0x44, 0x00, 0x00, + 0x02, 0x58, 0x04, 0xb0, 0x00, 0x00, + 0x2b, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x98, 0x41, 0x30, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_12[72] = { + 0x88, 0x91, 0x11, 0x20, 0x00, 0x00, + 0x40, 0x54, 0x80, 0xa8, 0x00, 0x00, + 0x82, 0x63, 0x04, 0xc4, 0x00, 0x00, + 0x21, 0xa4, 0x43, 0x48, 0x00, 0x00, + 0x10, 0x64, 0x20, 0xc8, 0x00, 0x00, + 0x44, 0x0a, 0x88, 0x14, 0x00, 0x00, + 0x10, 0xc8, 0x21, 0x90, 0x00, 0x00, + 0x4d, 0x2a, 0x9a, 0x54, 0x00, 0x00, + 0x38, 0x02, 0x70, 0x04, 0x00, 0x00, + 0x17, 0x48, 0x2e, 0x90, 0x00, 0x00, + 0x90, 0x85, 0x21, 0x08, 0x00, 0x00, + 0x72, 0x14, 0xe4, 0x28, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_13[78] = { + 0x62, 0xa2, 0xc5, 0x44, 0x00, 0x00, + 0x34, 0x44, 0x68, 0x88, 0x00, 0x00, + 0x40, 0x4a, 0x80, 0x94, 0x00, 0x00, + 0xc4, 0x05, 0x88, 0x08, 0x00, 0x00, + 0x08, 0x60, 0x10, 0xc0, 0x00, 0x00, + 0x94, 0x13, 0x28, 0x24, 0x00, 0x00, + 0x88, 0xc1, 0x11, 0x80, 0x00, 0x00, + 0x21, 0x32, 0x42, 0x64, 0x00, 0x00, + 0xc1, 0x41, 0x82, 0x80, 0x00, 0x00, + 0x10, 0x68, 0x20, 0xd0, 0x00, 0x00, + 0x06, 0x90, 0x0d, 0x20, 0x00, 0x00, + 0x59, 0x00, 0xb2, 0x00, 0x00, 0x00, + 0x0a, 0x0c, 0x14, 0x18, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_14[84] = { + 0x40, 0x82, 0x81, 0x04, 0x00, 0x00, + 0x15, 0x54, 0x2a, 0xa8, 0x00, 0x00, + 0x88, 0x13, 0x10, 0x24, 0x00, 0x00, + 0xc0, 0x11, 0x80, 0x20, 0x00, 0x00, + 0x80, 0xa1, 0x01, 0x40, 0x00, 0x00, + 0x01, 0x22, 0x02, 0x44, 0x00, 0x00, + 0x40, 0x2c, 0x80, 0x58, 0x00, 0x00, + 0x22, 0x02, 0x44, 0x04, 0x00, 0x00, + 0x90, 0x05, 0x20, 0x08, 0x00, 0x00, + 0x12, 0x40, 0x24, 0x80, 0x00, 0x00, + 0x5d, 0x00, 0xba, 0x00, 0x00, 0x00, + 0x20, 0x54, 0x40, 0xa8, 0x00, 0x00, + 0x86, 0x09, 0x0c, 0x10, 0x00, 0x00, + 0x28, 0x88, 0x51, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_15[90] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x31, 0x10, 0x62, 0x20, 0x00, 0x00, + 0x58, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x88, 0x21, 0x10, 0x40, 0x00, 0x00, + 0x44, 0x02, 0x88, 0x04, 0x00, 0x00, + 0x29, 0x04, 0x52, 0x08, 0x00, 0x00, + 0x82, 0xa1, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x1a, 0x14, 0x34, 0x00, 0x00, + 0x11, 0xe0, 0x23, 0xc0, 0x00, 0x00, + 0x84, 0x05, 0x08, 0x08, 0x00, 0x00, + 0x86, 0x41, 0x0c, 0x80, 0x00, 0x00, + 0x00, 0x86, 0x01, 0x0c, 0x00, 0x00, + 0x44, 0x48, 0x88, 0x90, 0x00, 0x00, + 0x10, 0x98, 0x21, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_16[96] = { + 0x90, 0x23, 0x20, 0x44, 0x00, 0x00, + 0x09, 0x50, 0x12, 0xa0, 0x00, 0x00, + 0x00, 0x6a, 0x00, 0xd4, 0x00, 0x00, + 0x20, 0x34, 0x40, 0x68, 0x00, 0x00, + 0x14, 0x44, 0x28, 0x88, 0x00, 0x00, + 0xc2, 0x11, 0x84, 0x20, 0x00, 0x00, + 0x00, 0xc6, 0x01, 0x8c, 0x00, 0x00, + 0x65, 0x80, 0xcb, 0x00, 0x00, 0x00, + 0x62, 0xa2, 0xc5, 0x44, 0x00, 0x00, + 0xb1, 0x15, 0x62, 0x28, 0x00, 0x00, + 0x18, 0x6a, 0x30, 0xd4, 0x00, 0x00, + 0x44, 0xd4, 0x89, 0xa8, 0x00, 0x00, + 0x13, 0x64, 0x26, 0xc8, 0x00, 0x00, + 0x49, 0x1a, 0x92, 0x34, 0x00, 0x00, + 0x86, 0x8d, 0x0d, 0x18, 0x00, 0x00, + 0xce, 0x58, 0xa0, 0x14, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_17[102] = { + 0x90, 0x23, 0x20, 0x44, 0x00, 0x00, + 0x09, 0x50, 0x12, 0xa0, 0x00, 0x00, + 0x00, 0x6a, 0x00, 0xd4, 0x00, 0x00, + 0x20, 0x34, 0x40, 0x68, 0x00, 0x00, + 0x14, 0x44, 0x28, 0x88, 0x00, 0x00, + 0xc2, 0x11, 0x84, 0x20, 0x00, 0x00, + 0x00, 0xc6, 0x01, 0x8c, 0x00, 0x00, + 0x65, 0x80, 0xcb, 0x00, 0x00, 0x00, + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x24, 0x44, 0x48, 0x88, 0x00, 0x00, + 0xc0, 0x51, 0x80, 0xa0, 0x00, 0x00, + 0x03, 0x0c, 0x06, 0x18, 0x00, 0x00, + 0x16, 0x28, 0x2c, 0x50, 0x00, 0x00, + 0x89, 0x01, 0x12, 0x00, 0x00, 0x00, + 0x82, 0x91, 0x05, 0x20, 0x00, 0x00, + 0x08, 0xa4, 0x11, 0x48, 0x00, 0x00, + 0x90, 0x49, 0x20, 0x90, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_18[108] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x24, 0x44, 0x48, 0x88, 0x00, 0x00, + 0xc0, 0x51, 0x80, 0xa0, 0x00, 0x00, + 0x03, 0x0c, 0x06, 0x18, 0x00, 0x00, + 0x16, 0x28, 0x2c, 0x50, 0x00, 0x00, + 0x89, 0x01, 0x12, 0x00, 0x00, 0x00, + 0x82, 0x91, 0x05, 0x20, 0x00, 0x00, + 0x08, 0xa4, 0x11, 0x48, 0x00, 0x00, + 0x90, 0x49, 0x20, 0x90, 0x00, 0x00, + 0x90, 0x23, 0x20, 0x44, 0x00, 0x00, + 0x09, 0x50, 0x12, 0xa0, 0x00, 0x00, + 0x00, 0x6a, 0x00, 0xd4, 0x00, 0x00, + 0x20, 0x34, 0x40, 0x68, 0x00, 0x00, + 0x14, 0x44, 0x28, 0x88, 0x00, 0x00, + 0xc2, 0x11, 0x84, 0x20, 0x00, 0x00, + 0x00, 0xc6, 0x01, 0x8c, 0x00, 0x00, + 0x65, 0x80, 0xcb, 0x00, 0x00, 0x00, + 0x00, 0xb2, 0x47, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_19[114] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x24, 0x44, 0x48, 0x88, 0x00, 0x00, + 0xc0, 0x51, 0x80, 0xa0, 0x00, 0x00, + 0x03, 0x0c, 0x06, 0x18, 0x00, 0x00, + 0x16, 0x28, 0x2c, 0x50, 0x00, 0x00, + 0x89, 0x01, 0x12, 0x00, 0x00, 0x00, + 0x82, 0x91, 0x05, 0x20, 0x00, 0x00, + 0x08, 0xa4, 0x11, 0x48, 0x00, 0x00, + 0x90, 0x49, 0x20, 0x90, 0x00, 0x00, + 0xc0, 0xa1, 0x81, 0x40, 0x00, 0x00, + 0x15, 0x56, 0x2a, 0xac, 0x00, 0x00, + 0x74, 0x40, 0xe8, 0x80, 0x00, 0x00, + 0x00, 0x9c, 0x01, 0x38, 0x00, 0x00, + 0x01, 0x2c, 0x02, 0x58, 0x00, 0x00, + 0x44, 0x92, 0x89, 0x24, 0x00, 0x00, + 0x88, 0x51, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0xa4, 0x41, 0x48, 0x00, 0x00, + 0xaa, 0x05, 0x54, 0x08, 0x00, 0x00, + 0x02, 0x62, 0x04, 0xc4, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_2[12] = { + 0xec, 0xeb, 0xd9, 0xd4, 0x00, 0x00, + 0xbb, 0x9d, 0x77, 0x38, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_20[120] = { + 0xc0, 0xa1, 0x81, 0x40, 0x00, 0x00, + 0x15, 0x56, 0x2a, 0xac, 0x00, 0x00, + 0x74, 0x40, 0xe8, 0x80, 0x00, 0x00, + 0x00, 0x9c, 0x01, 0x38, 0x00, 0x00, + 0x01, 0x2c, 0x02, 0x58, 0x00, 0x00, + 0x44, 0x92, 0x89, 0x24, 0x00, 0x00, + 0x88, 0x51, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0xa4, 0x41, 0x48, 0x00, 0x00, + 0xaa, 0x05, 0x54, 0x08, 0x00, 0x00, + 0x02, 0x62, 0x04, 0xc4, 0x00, 0x00, + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x24, 0x44, 0x48, 0x88, 0x00, 0x00, + 0xc0, 0x51, 0x80, 0xa0, 0x00, 0x00, + 0x03, 0x0c, 0x06, 0x18, 0x00, 0x00, + 0x16, 0x28, 0x2c, 0x50, 0x00, 0x00, + 0x89, 0x01, 0x12, 0x00, 0x00, 0x00, + 0x82, 0x91, 0x05, 0x20, 0x00, 0x00, + 0x08, 0xa4, 0x11, 0x48, 0x00, 0x00, + 0x90, 0x49, 0x20, 0x90, 0x00, 0x00, + 0x51, 0x88, 0xd1, 0x78, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_21[126] = { + 0xc0, 0xa1, 0x81, 0x40, 0x00, 0x00, + 0x15, 0x56, 0x2a, 0xac, 0x00, 0x00, + 0x74, 0x40, 0xe8, 0x80, 0x00, 0x00, + 0x00, 0x9c, 0x01, 0x38, 0x00, 0x00, + 0x01, 0x2c, 0x02, 0x58, 0x00, 0x00, + 0x44, 0x92, 0x89, 0x24, 0x00, 0x00, + 0x88, 0x51, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0xa4, 0x41, 0x48, 0x00, 0x00, + 0xaa, 0x05, 0x54, 0x08, 0x00, 0x00, + 0x02, 0x62, 0x04, 0xc4, 0x00, 0x00, + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0xf1, 0x11, 0xe2, 0x20, 0x00, 0x00, + 0x10, 0x0e, 0x20, 0x1c, 0x00, 0x00, + 0x10, 0xb0, 0x21, 0x60, 0x00, 0x00, + 0x24, 0x24, 0x48, 0x48, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x00, 0xc4, 0x01, 0x88, 0x00, 0x00, + 0x04, 0xa2, 0x09, 0x44, 0x00, 0x00, + 0x02, 0x58, 0x04, 0xb0, 0x00, 0x00, + 0x2b, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x98, 0x41, 0x30, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_22[132] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0xf1, 0x11, 0xe2, 0x20, 0x00, 0x00, + 0x10, 0x0e, 0x20, 0x1c, 0x00, 0x00, + 0x10, 0xb0, 0x21, 0x60, 0x00, 0x00, + 0x24, 0x24, 0x48, 0x48, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x00, 0xc4, 0x01, 0x88, 0x00, 0x00, + 0x04, 0xa2, 0x09, 0x44, 0x00, 0x00, + 0x02, 0x58, 0x04, 0xb0, 0x00, 0x00, + 0x2b, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x98, 0x41, 0x30, 0x80, 0x00, 0x00, + 0xc0, 0xa1, 0x81, 0x40, 0x00, 0x00, + 0x15, 0x56, 0x2a, 0xac, 0x00, 0x00, + 0x74, 0x40, 0xe8, 0x80, 0x00, 0x00, + 0x00, 0x9c, 0x01, 0x38, 0x00, 0x00, + 0x01, 0x2c, 0x02, 0x58, 0x00, 0x00, + 0x44, 0x92, 0x89, 0x24, 0x00, 0x00, + 0x88, 0x51, 0x10, 0xa0, 0x00, 0x00, + 0x20, 0xa4, 0x41, 0x48, 0x00, 0x00, + 0xaa, 0x05, 0x54, 0x08, 0x00, 0x00, + 0x02, 0x62, 0x04, 0xc4, 0x00, 0x00, + 0x03, 0x10, 0x18, 0x74, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_23[138] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0xf1, 0x11, 0xe2, 0x20, 0x00, 0x00, + 0x10, 0x0e, 0x20, 0x1c, 0x00, 0x00, + 0x10, 0xb0, 0x21, 0x60, 0x00, 0x00, + 0x24, 0x24, 0x48, 0x48, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x00, 0xc4, 0x01, 0x88, 0x00, 0x00, + 0x04, 0xa2, 0x09, 0x44, 0x00, 0x00, + 0x02, 0x58, 0x04, 0xb0, 0x00, 0x00, + 0x2b, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x98, 0x41, 0x30, 0x80, 0x00, 0x00, + 0x88, 0x91, 0x11, 0x20, 0x00, 0x00, + 0x40, 0x54, 0x80, 0xa8, 0x00, 0x00, + 0x82, 0x63, 0x04, 0xc4, 0x00, 0x00, + 0x21, 0xa4, 0x43, 0x48, 0x00, 0x00, + 0x10, 0x64, 0x20, 0xc8, 0x00, 0x00, + 0x44, 0x0a, 0x88, 0x14, 0x00, 0x00, + 0x10, 0xc8, 0x21, 0x90, 0x00, 0x00, + 0x4d, 0x2a, 0x9a, 0x54, 0x00, 0x00, + 0x38, 0x02, 0x70, 0x04, 0x00, 0x00, + 0x17, 0x48, 0x2e, 0x90, 0x00, 0x00, + 0x90, 0x85, 0x21, 0x08, 0x00, 0x00, + 0x72, 0x14, 0xe4, 0x28, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_24[144] = { + 0x88, 0x91, 0x11, 0x20, 0x00, 0x00, + 0x40, 0x54, 0x80, 0xa8, 0x00, 0x00, + 0x82, 0x63, 0x04, 0xc4, 0x00, 0x00, + 0x21, 0xa4, 0x43, 0x48, 0x00, 0x00, + 0x10, 0x64, 0x20, 0xc8, 0x00, 0x00, + 0x44, 0x0a, 0x88, 0x14, 0x00, 0x00, + 0x10, 0xc8, 0x21, 0x90, 0x00, 0x00, + 0x4d, 0x2a, 0x9a, 0x54, 0x00, 0x00, + 0x38, 0x02, 0x70, 0x04, 0x00, 0x00, + 0x17, 0x48, 0x2e, 0x90, 0x00, 0x00, + 0x90, 0x85, 0x21, 0x08, 0x00, 0x00, + 0x72, 0x14, 0xe4, 0x28, 0x00, 0x00, + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0xf1, 0x11, 0xe2, 0x20, 0x00, 0x00, + 0x10, 0x0e, 0x20, 0x1c, 0x00, 0x00, + 0x10, 0xb0, 0x21, 0x60, 0x00, 0x00, + 0x24, 0x24, 0x48, 0x48, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x00, 0xc4, 0x01, 0x88, 0x00, 0x00, + 0x04, 0xa2, 0x09, 0x44, 0x00, 0x00, + 0x02, 0x58, 0x04, 0xb0, 0x00, 0x00, + 0x2b, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x98, 0x41, 0x30, 0x80, 0x00, 0x00, + 0xf3, 0x4d, 0x1c, 0x70, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_25[150] = { + 0x88, 0x91, 0x11, 0x20, 0x00, 0x00, + 0x40, 0x54, 0x80, 0xa8, 0x00, 0x00, + 0x82, 0x63, 0x04, 0xc4, 0x00, 0x00, + 0x21, 0xa4, 0x43, 0x48, 0x00, 0x00, + 0x10, 0x64, 0x20, 0xc8, 0x00, 0x00, + 0x44, 0x0a, 0x88, 0x14, 0x00, 0x00, + 0x10, 0xc8, 0x21, 0x90, 0x00, 0x00, + 0x4d, 0x2a, 0x9a, 0x54, 0x00, 0x00, + 0x38, 0x02, 0x70, 0x04, 0x00, 0x00, + 0x17, 0x48, 0x2e, 0x90, 0x00, 0x00, + 0x90, 0x85, 0x21, 0x08, 0x00, 0x00, + 0x72, 0x14, 0xe4, 0x28, 0x00, 0x00, + 0x62, 0xa2, 0xc5, 0x44, 0x00, 0x00, + 0x34, 0x44, 0x68, 0x88, 0x00, 0x00, + 0x40, 0x4a, 0x80, 0x94, 0x00, 0x00, + 0xc4, 0x05, 0x88, 0x08, 0x00, 0x00, + 0x08, 0x60, 0x10, 0xc0, 0x00, 0x00, + 0x94, 0x13, 0x28, 0x24, 0x00, 0x00, + 0x88, 0xc1, 0x11, 0x80, 0x00, 0x00, + 0x21, 0x32, 0x42, 0x64, 0x00, 0x00, + 0xc1, 0x41, 0x82, 0x80, 0x00, 0x00, + 0x10, 0x68, 0x20, 0xd0, 0x00, 0x00, + 0x06, 0x90, 0x0d, 0x20, 0x00, 0x00, + 0x59, 0x00, 0xb2, 0x00, 0x00, 0x00, + 0x0a, 0x0c, 0x14, 0x18, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_26[156] = { + 0x62, 0xa2, 0xc5, 0x44, 0x00, 0x00, + 0x34, 0x44, 0x68, 0x88, 0x00, 0x00, + 0x40, 0x4a, 0x80, 0x94, 0x00, 0x00, + 0xc4, 0x05, 0x88, 0x08, 0x00, 0x00, + 0x08, 0x60, 0x10, 0xc0, 0x00, 0x00, + 0x94, 0x13, 0x28, 0x24, 0x00, 0x00, + 0x88, 0xc1, 0x11, 0x80, 0x00, 0x00, + 0x21, 0x32, 0x42, 0x64, 0x00, 0x00, + 0xc1, 0x41, 0x82, 0x80, 0x00, 0x00, + 0x10, 0x68, 0x20, 0xd0, 0x00, 0x00, + 0x06, 0x90, 0x0d, 0x20, 0x00, 0x00, + 0x59, 0x00, 0xb2, 0x00, 0x00, 0x00, + 0x0a, 0x0c, 0x14, 0x18, 0x00, 0x00, + 0x88, 0x91, 0x11, 0x20, 0x00, 0x00, + 0x40, 0x54, 0x80, 0xa8, 0x00, 0x00, + 0x82, 0x63, 0x04, 0xc4, 0x00, 0x00, + 0x21, 0xa4, 0x43, 0x48, 0x00, 0x00, + 0x10, 0x64, 0x20, 0xc8, 0x00, 0x00, + 0x44, 0x0a, 0x88, 0x14, 0x00, 0x00, + 0x10, 0xc8, 0x21, 0x90, 0x00, 0x00, + 0x4d, 0x2a, 0x9a, 0x54, 0x00, 0x00, + 0x38, 0x02, 0x70, 0x04, 0x00, 0x00, + 0x17, 0x48, 0x2e, 0x90, 0x00, 0x00, + 0x90, 0x85, 0x21, 0x08, 0x00, 0x00, + 0x72, 0x14, 0xe4, 0x28, 0x00, 0x00, + 0x83, 0x11, 0xad, 0xe8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_27[162] = { + 0x62, 0xa2, 0xc5, 0x44, 0x00, 0x00, + 0x34, 0x44, 0x68, 0x88, 0x00, 0x00, + 0x40, 0x4a, 0x80, 0x94, 0x00, 0x00, + 0xc4, 0x05, 0x88, 0x08, 0x00, 0x00, + 0x08, 0x60, 0x10, 0xc0, 0x00, 0x00, + 0x94, 0x13, 0x28, 0x24, 0x00, 0x00, + 0x88, 0xc1, 0x11, 0x80, 0x00, 0x00, + 0x21, 0x32, 0x42, 0x64, 0x00, 0x00, + 0xc1, 0x41, 0x82, 0x80, 0x00, 0x00, + 0x10, 0x68, 0x20, 0xd0, 0x00, 0x00, + 0x06, 0x90, 0x0d, 0x20, 0x00, 0x00, + 0x59, 0x00, 0xb2, 0x00, 0x00, 0x00, + 0x0a, 0x0c, 0x14, 0x18, 0x00, 0x00, + 0x40, 0x82, 0x81, 0x04, 0x00, 0x00, + 0x15, 0x54, 0x2a, 0xa8, 0x00, 0x00, + 0x88, 0x13, 0x10, 0x24, 0x00, 0x00, + 0xc0, 0x11, 0x80, 0x20, 0x00, 0x00, + 0x80, 0xa1, 0x01, 0x40, 0x00, 0x00, + 0x01, 0x22, 0x02, 0x44, 0x00, 0x00, + 0x40, 0x2c, 0x80, 0x58, 0x00, 0x00, + 0x22, 0x02, 0x44, 0x04, 0x00, 0x00, + 0x90, 0x05, 0x20, 0x08, 0x00, 0x00, + 0x12, 0x40, 0x24, 0x80, 0x00, 0x00, + 0x5d, 0x00, 0xba, 0x00, 0x00, 0x00, + 0x20, 0x54, 0x40, 0xa8, 0x00, 0x00, + 0x86, 0x09, 0x0c, 0x10, 0x00, 0x00, + 0x28, 0x88, 0x51, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_28[168] = { + 0x40, 0x82, 0x81, 0x04, 0x00, 0x00, + 0x15, 0x54, 0x2a, 0xa8, 0x00, 0x00, + 0x88, 0x13, 0x10, 0x24, 0x00, 0x00, + 0xc0, 0x11, 0x80, 0x20, 0x00, 0x00, + 0x80, 0xa1, 0x01, 0x40, 0x00, 0x00, + 0x01, 0x22, 0x02, 0x44, 0x00, 0x00, + 0x40, 0x2c, 0x80, 0x58, 0x00, 0x00, + 0x22, 0x02, 0x44, 0x04, 0x00, 0x00, + 0x90, 0x05, 0x20, 0x08, 0x00, 0x00, + 0x12, 0x40, 0x24, 0x80, 0x00, 0x00, + 0x5d, 0x00, 0xba, 0x00, 0x00, 0x00, + 0x20, 0x54, 0x40, 0xa8, 0x00, 0x00, + 0x86, 0x09, 0x0c, 0x10, 0x00, 0x00, + 0x28, 0x88, 0x51, 0x10, 0x00, 0x00, + 0x62, 0xa2, 0xc5, 0x44, 0x00, 0x00, + 0x34, 0x44, 0x68, 0x88, 0x00, 0x00, + 0x40, 0x4a, 0x80, 0x94, 0x00, 0x00, + 0xc4, 0x05, 0x88, 0x08, 0x00, 0x00, + 0x08, 0x60, 0x10, 0xc0, 0x00, 0x00, + 0x94, 0x13, 0x28, 0x24, 0x00, 0x00, + 0x88, 0xc1, 0x11, 0x80, 0x00, 0x00, + 0x21, 0x32, 0x42, 0x64, 0x00, 0x00, + 0xc1, 0x41, 0x82, 0x80, 0x00, 0x00, + 0x10, 0x68, 0x20, 0xd0, 0x00, 0x00, + 0x06, 0x90, 0x0d, 0x20, 0x00, 0x00, + 0x59, 0x00, 0xb2, 0x00, 0x00, 0x00, + 0x0a, 0x0c, 0x14, 0x18, 0x00, 0x00, + 0x94, 0x59, 0x03, 0x18, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_29[174] = { + 0x40, 0x82, 0x81, 0x04, 0x00, 0x00, + 0x15, 0x54, 0x2a, 0xa8, 0x00, 0x00, + 0x88, 0x13, 0x10, 0x24, 0x00, 0x00, + 0xc0, 0x11, 0x80, 0x20, 0x00, 0x00, + 0x80, 0xa1, 0x01, 0x40, 0x00, 0x00, + 0x01, 0x22, 0x02, 0x44, 0x00, 0x00, + 0x40, 0x2c, 0x80, 0x58, 0x00, 0x00, + 0x22, 0x02, 0x44, 0x04, 0x00, 0x00, + 0x90, 0x05, 0x20, 0x08, 0x00, 0x00, + 0x12, 0x40, 0x24, 0x80, 0x00, 0x00, + 0x5d, 0x00, 0xba, 0x00, 0x00, 0x00, + 0x20, 0x54, 0x40, 0xa8, 0x00, 0x00, + 0x86, 0x09, 0x0c, 0x10, 0x00, 0x00, + 0x28, 0x88, 0x51, 0x10, 0x00, 0x00, + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x31, 0x10, 0x62, 0x20, 0x00, 0x00, + 0x58, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x88, 0x21, 0x10, 0x40, 0x00, 0x00, + 0x44, 0x02, 0x88, 0x04, 0x00, 0x00, + 0x29, 0x04, 0x52, 0x08, 0x00, 0x00, + 0x82, 0xa1, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x1a, 0x14, 0x34, 0x00, 0x00, + 0x11, 0xe0, 0x23, 0xc0, 0x00, 0x00, + 0x84, 0x05, 0x08, 0x08, 0x00, 0x00, + 0x86, 0x41, 0x0c, 0x80, 0x00, 0x00, + 0x00, 0x86, 0x01, 0x0c, 0x00, 0x00, + 0x44, 0x48, 0x88, 0x90, 0x00, 0x00, + 0x10, 0x98, 0x21, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_3[18] = { + 0xac, 0x93, 0x59, 0x24, 0x00, 0x00, + 0x55, 0x4a, 0xaa, 0x94, 0x00, 0x00, + 0x43, 0x36, 0x86, 0x6c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_30[180] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x31, 0x10, 0x62, 0x20, 0x00, 0x00, + 0x58, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0x01, 0x12, 0x02, 0x24, 0x00, 0x00, + 0x88, 0x21, 0x10, 0x40, 0x00, 0x00, + 0x44, 0x02, 0x88, 0x04, 0x00, 0x00, + 0x29, 0x04, 0x52, 0x08, 0x00, 0x00, + 0x82, 0xa1, 0x05, 0x40, 0x00, 0x00, + 0x0a, 0x1a, 0x14, 0x34, 0x00, 0x00, + 0x11, 0xe0, 0x23, 0xc0, 0x00, 0x00, + 0x84, 0x05, 0x08, 0x08, 0x00, 0x00, + 0x86, 0x41, 0x0c, 0x80, 0x00, 0x00, + 0x00, 0x86, 0x01, 0x0c, 0x00, 0x00, + 0x44, 0x48, 0x88, 0x90, 0x00, 0x00, + 0x10, 0x98, 0x21, 0x30, 0x00, 0x00, + 0x40, 0x82, 0x81, 0x04, 0x00, 0x00, + 0x15, 0x54, 0x2a, 0xa8, 0x00, 0x00, + 0x88, 0x13, 0x10, 0x24, 0x00, 0x00, + 0xc0, 0x11, 0x80, 0x20, 0x00, 0x00, + 0x80, 0xa1, 0x01, 0x40, 0x00, 0x00, + 0x01, 0x22, 0x02, 0x44, 0x00, 0x00, + 0x40, 0x2c, 0x80, 0x58, 0x00, 0x00, + 0x22, 0x02, 0x44, 0x04, 0x00, 0x00, + 0x90, 0x05, 0x20, 0x08, 0x00, 0x00, + 0x12, 0x40, 0x24, 0x80, 0x00, 0x00, + 0x5d, 0x00, 0xba, 0x00, 0x00, 0x00, + 0x20, 0x54, 0x40, 0xa8, 0x00, 0x00, + 0x86, 0x09, 0x0c, 0x10, 0x00, 0x00, + 0x28, 0x88, 0x51, 0x10, 0x00, 0x00, + 0x46, 0xf1, 0xef, 0xec, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_4[24] = { + 0x25, 0xaa, 0x4b, 0x54, 0x00, 0x00, + 0x95, 0x55, 0x2a, 0xa8, 0x00, 0x00, + 0x1a, 0x6a, 0x34, 0xd4, 0x00, 0x00, + 0x43, 0xd4, 0x87, 0xa8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_5[30] = { + 0x64, 0xa2, 0xc9, 0x44, 0x00, 0x00, + 0x25, 0x54, 0x4a, 0xa8, 0x00, 0x00, + 0x49, 0x68, 0x92, 0xd0, 0x00, 0x00, + 0x53, 0x90, 0xa7, 0x20, 0x00, 0x00, + 0x8e, 0x31, 0x1c, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_6[36] = { + 0x62, 0x8a, 0xc5, 0x14, 0x00, 0x00, + 0x15, 0x54, 0x2a, 0xa8, 0x00, 0x00, + 0x4c, 0x46, 0x98, 0x8c, 0x00, 0x00, + 0x52, 0x94, 0xa5, 0x28, 0x00, 0x00, + 0x23, 0x64, 0x46, 0xc8, 0x00, 0x00, + 0x8a, 0x59, 0x14, 0xb0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_7[42] = { + 0x62, 0xa2, 0xc5, 0x44, 0x00, 0x00, + 0xb1, 0x15, 0x62, 0x28, 0x00, 0x00, + 0x18, 0x6a, 0x30, 0xd4, 0x00, 0x00, + 0x44, 0xd4, 0x89, 0xa8, 0x00, 0x00, + 0x13, 0x64, 0x26, 0xc8, 0x00, 0x00, + 0x49, 0x1a, 0x92, 0x34, 0x00, 0x00, + 0x86, 0x8d, 0x0d, 0x18, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_8[48] = { + 0x90, 0x23, 0x20, 0x44, 0x00, 0x00, + 0x09, 0x50, 0x12, 0xa0, 0x00, 0x00, + 0x00, 0x6a, 0x00, 0xd4, 0x00, 0x00, + 0x20, 0x34, 0x40, 0x68, 0x00, 0x00, + 0x14, 0x44, 0x28, 0x88, 0x00, 0x00, + 0xc2, 0x11, 0x84, 0x20, 0x00, 0x00, + 0x00, 0xc6, 0x01, 0x8c, 0x00, 0x00, + 0x65, 0x80, 0xcb, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom30_9[54] = { + 0x62, 0x22, 0xc4, 0x44, 0x00, 0x00, + 0x24, 0x44, 0x48, 0x88, 0x00, 0x00, + 0xc0, 0x51, 0x80, 0xa0, 0x00, 0x00, + 0x03, 0x0c, 0x06, 0x18, 0x00, 0x00, + 0x16, 0x28, 0x2c, 0x50, 0x00, 0x00, + 0x89, 0x01, 0x12, 0x00, 0x00, 0x00, + 0x82, 0x91, 0x05, 0x20, 0x00, 0x00, + 0x08, 0xa4, 0x11, 0x48, 0x00, 0x00, + 0x90, 0x49, 0x20, 0x90, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_1[6] = { + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_10[60] = { + 0xc0, 0xa0, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x56, 0x21, 0x44, 0x00, 0x00, + 0x74, 0x40, 0x02, 0x4a, 0x00, 0x00, + 0x00, 0x9c, 0x16, 0x84, 0x00, 0x00, + 0x01, 0x2d, 0xb0, 0x40, 0x00, 0x00, + 0x44, 0x93, 0x05, 0x18, 0x00, 0x00, + 0x88, 0x50, 0x48, 0x94, 0x00, 0x00, + 0x20, 0xa4, 0x70, 0x30, 0x00, 0x00, + 0xaa, 0x04, 0x54, 0x4a, 0x00, 0x00, + 0x02, 0x63, 0x09, 0x24, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_11[66] = { + 0x62, 0x22, 0xaa, 0xaa, 0x00, 0x00, + 0xf1, 0x10, 0x54, 0x44, 0x00, 0x00, + 0x10, 0x0e, 0x62, 0x22, 0x00, 0x00, + 0x10, 0xb1, 0x06, 0x84, 0x00, 0x00, + 0x24, 0x24, 0x0d, 0x30, 0x00, 0x00, + 0x01, 0x12, 0x81, 0xc2, 0x00, 0x00, + 0x00, 0xc4, 0x58, 0x88, 0x00, 0x00, + 0x04, 0xa3, 0xb0, 0x50, 0x00, 0x00, + 0x02, 0x59, 0x25, 0x02, 0x00, 0x00, + 0x2b, 0x01, 0x08, 0x64, 0x00, 0x00, + 0x98, 0x40, 0xd0, 0x18, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_12[72] = { + 0x88, 0x91, 0x08, 0x62, 0x00, 0x00, + 0x40, 0x54, 0x31, 0x44, 0x00, 0x00, + 0x82, 0x62, 0x9c, 0x02, 0x00, 0x00, + 0x21, 0xa4, 0x89, 0x90, 0x00, 0x00, + 0x10, 0x64, 0x1d, 0x20, 0x00, 0x00, + 0x44, 0x0a, 0x41, 0x98, 0x00, 0x00, + 0x10, 0xc9, 0x26, 0x80, 0x00, 0x00, + 0x4d, 0x2a, 0x5a, 0x20, 0x00, 0x00, + 0x38, 0x02, 0x62, 0x88, 0x00, 0x00, + 0x17, 0x49, 0x80, 0x46, 0x00, 0x00, + 0x90, 0x84, 0x22, 0x4a, 0x00, 0x00, + 0x72, 0x15, 0xd1, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_13[78] = { + 0x62, 0xa2, 0x8a, 0x2a, 0x00, 0x00, + 0x34, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x40, 0x4b, 0x2c, 0x18, 0x00, 0x00, + 0xc4, 0x04, 0x18, 0xa0, 0x00, 0x00, + 0x08, 0x60, 0xc4, 0x08, 0x00, 0x00, + 0x94, 0x12, 0x92, 0x0c, 0x00, 0x00, + 0x88, 0xc0, 0x23, 0x04, 0x00, 0x00, + 0x21, 0x32, 0x24, 0x70, 0x00, 0x00, + 0xc1, 0x40, 0x80, 0xe2, 0x00, 0x00, + 0x10, 0x69, 0x51, 0x14, 0x00, 0x00, + 0x06, 0x90, 0x11, 0x42, 0x00, 0x00, + 0x59, 0x01, 0x41, 0x80, 0x00, 0x00, + 0x0a, 0x0d, 0x8a, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_14[84] = { + 0x40, 0x82, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x54, 0x44, 0x14, 0x00, 0x00, + 0x88, 0x13, 0x09, 0xa0, 0x00, 0x00, + 0xc0, 0x10, 0x19, 0x14, 0x00, 0x00, + 0x80, 0xa0, 0x30, 0x0c, 0x00, 0x00, + 0x01, 0x22, 0x60, 0x06, 0x00, 0x00, + 0x40, 0x2c, 0xc2, 0x10, 0x00, 0x00, + 0x22, 0x02, 0x80, 0x22, 0x00, 0x00, + 0x90, 0x04, 0x20, 0x58, 0x00, 0x00, + 0x12, 0x40, 0x12, 0xc0, 0x00, 0x00, + 0x5d, 0x00, 0x01, 0x28, 0x00, 0x00, + 0x20, 0x54, 0xa4, 0x80, 0x00, 0x00, + 0x86, 0x09, 0x48, 0x48, 0x00, 0x00, + 0x28, 0x89, 0x05, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_15[90] = { + 0x62, 0x22, 0xaa, 0x22, 0x00, 0x00, + 0x31, 0x10, 0x44, 0x44, 0x00, 0x00, + 0x58, 0x00, 0x22, 0x22, 0x00, 0x00, + 0x01, 0x13, 0x00, 0x8a, 0x00, 0x00, + 0x88, 0x20, 0x40, 0x34, 0x00, 0x00, + 0x44, 0x02, 0x10, 0xd0, 0x00, 0x00, + 0x29, 0x04, 0x45, 0x08, 0x00, 0x00, + 0x82, 0xa0, 0x90, 0x12, 0x00, 0x00, + 0x0a, 0x1a, 0x0e, 0x02, 0x00, 0x00, + 0x11, 0xe1, 0x28, 0x40, 0x00, 0x00, + 0x84, 0x05, 0x04, 0x0c, 0x00, 0x00, + 0x86, 0x40, 0xc0, 0x90, 0x00, 0x00, + 0x00, 0x87, 0x13, 0x00, 0x00, 0x00, + 0x44, 0x48, 0x01, 0x1c, 0x00, 0x00, + 0x10, 0x98, 0x30, 0x44, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_16[96] = { + 0x90, 0x22, 0x40, 0xa8, 0x00, 0x00, + 0x09, 0x50, 0x31, 0x10, 0x00, 0x00, + 0x00, 0x6b, 0x08, 0x0e, 0x00, 0x00, + 0x20, 0x34, 0xc0, 0x90, 0x00, 0x00, + 0x14, 0x44, 0x25, 0x04, 0x00, 0x00, + 0xc2, 0x11, 0x02, 0x82, 0x00, 0x00, + 0x00, 0xc6, 0x80, 0xc4, 0x00, 0x00, + 0x65, 0x80, 0x2c, 0x60, 0x00, 0x00, + 0x62, 0xa2, 0x8a, 0xa2, 0x00, 0x00, + 0xb1, 0x14, 0x44, 0x54, 0x00, 0x00, + 0x18, 0x6b, 0x22, 0x22, 0x00, 0x00, + 0x44, 0xd4, 0x5c, 0x10, 0x00, 0x00, + 0x13, 0x64, 0x90, 0x68, 0x00, 0x00, + 0x49, 0x1b, 0x20, 0x52, 0x00, 0x00, + 0x86, 0x8c, 0x13, 0x0c, 0x00, 0x00, + 0x8d, 0x94, 0xa9, 0xe0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_17[102] = { + 0x90, 0x22, 0x40, 0xa8, 0x00, 0x00, + 0x09, 0x50, 0x31, 0x10, 0x00, 0x00, + 0x00, 0x6b, 0x08, 0x0e, 0x00, 0x00, + 0x20, 0x34, 0xc0, 0x90, 0x00, 0x00, + 0x14, 0x44, 0x25, 0x04, 0x00, 0x00, + 0xc2, 0x11, 0x02, 0x82, 0x00, 0x00, + 0x00, 0xc6, 0x80, 0xc4, 0x00, 0x00, + 0x65, 0x80, 0x2c, 0x60, 0x00, 0x00, + 0x62, 0x22, 0xaa, 0xa2, 0x00, 0x00, + 0x24, 0x44, 0x44, 0x54, 0x00, 0x00, + 0xc0, 0x50, 0x0b, 0x0a, 0x00, 0x00, + 0x03, 0x0c, 0x12, 0x94, 0x00, 0x00, + 0x16, 0x29, 0x08, 0x64, 0x00, 0x00, + 0x89, 0x01, 0x80, 0x1a, 0x00, 0x00, + 0x82, 0x90, 0x41, 0x4c, 0x00, 0x00, + 0x08, 0xa4, 0x34, 0x12, 0x00, 0x00, + 0x90, 0x48, 0x88, 0xc8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_18[108] = { + 0x62, 0x22, 0xaa, 0xa2, 0x00, 0x00, + 0x24, 0x44, 0x44, 0x54, 0x00, 0x00, + 0xc0, 0x50, 0x0b, 0x0a, 0x00, 0x00, + 0x03, 0x0c, 0x12, 0x94, 0x00, 0x00, + 0x16, 0x29, 0x08, 0x64, 0x00, 0x00, + 0x89, 0x01, 0x80, 0x1a, 0x00, 0x00, + 0x82, 0x90, 0x41, 0x4c, 0x00, 0x00, + 0x08, 0xa4, 0x34, 0x12, 0x00, 0x00, + 0x90, 0x48, 0x88, 0xc8, 0x00, 0x00, + 0x90, 0x22, 0x40, 0xa8, 0x00, 0x00, + 0x09, 0x50, 0x31, 0x10, 0x00, 0x00, + 0x00, 0x6b, 0x08, 0x0e, 0x00, 0x00, + 0x20, 0x34, 0xc0, 0x90, 0x00, 0x00, + 0x14, 0x44, 0x25, 0x04, 0x00, 0x00, + 0xc2, 0x11, 0x02, 0x82, 0x00, 0x00, + 0x00, 0xc6, 0x80, 0xc4, 0x00, 0x00, + 0x65, 0x80, 0x2c, 0x60, 0x00, 0x00, + 0xe3, 0xd1, 0x2e, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_19[114] = { + 0x62, 0x22, 0xaa, 0xa2, 0x00, 0x00, + 0x24, 0x44, 0x44, 0x54, 0x00, 0x00, + 0xc0, 0x50, 0x0b, 0x0a, 0x00, 0x00, + 0x03, 0x0c, 0x12, 0x94, 0x00, 0x00, + 0x16, 0x29, 0x08, 0x64, 0x00, 0x00, + 0x89, 0x01, 0x80, 0x1a, 0x00, 0x00, + 0x82, 0x90, 0x41, 0x4c, 0x00, 0x00, + 0x08, 0xa4, 0x34, 0x12, 0x00, 0x00, + 0x90, 0x48, 0x88, 0xc8, 0x00, 0x00, + 0xc0, 0xa0, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x56, 0x21, 0x44, 0x00, 0x00, + 0x74, 0x40, 0x02, 0x4a, 0x00, 0x00, + 0x00, 0x9c, 0x16, 0x84, 0x00, 0x00, + 0x01, 0x2d, 0xb0, 0x40, 0x00, 0x00, + 0x44, 0x93, 0x05, 0x18, 0x00, 0x00, + 0x88, 0x50, 0x48, 0x94, 0x00, 0x00, + 0x20, 0xa4, 0x70, 0x30, 0x00, 0x00, + 0xaa, 0x04, 0x54, 0x4a, 0x00, 0x00, + 0x02, 0x63, 0x09, 0x24, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_2[12] = { + 0xec, 0xeb, 0x5d, 0x5c, 0x00, 0x00, + 0xbb, 0x9c, 0xf2, 0xf2, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_20[120] = { + 0xc0, 0xa0, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x56, 0x21, 0x44, 0x00, 0x00, + 0x74, 0x40, 0x02, 0x4a, 0x00, 0x00, + 0x00, 0x9c, 0x16, 0x84, 0x00, 0x00, + 0x01, 0x2d, 0xb0, 0x40, 0x00, 0x00, + 0x44, 0x93, 0x05, 0x18, 0x00, 0x00, + 0x88, 0x50, 0x48, 0x94, 0x00, 0x00, + 0x20, 0xa4, 0x70, 0x30, 0x00, 0x00, + 0xaa, 0x04, 0x54, 0x4a, 0x00, 0x00, + 0x02, 0x63, 0x09, 0x24, 0x00, 0x00, + 0x62, 0x22, 0xaa, 0xa2, 0x00, 0x00, + 0x24, 0x44, 0x44, 0x54, 0x00, 0x00, + 0xc0, 0x50, 0x0b, 0x0a, 0x00, 0x00, + 0x03, 0x0c, 0x12, 0x94, 0x00, 0x00, + 0x16, 0x29, 0x08, 0x64, 0x00, 0x00, + 0x89, 0x01, 0x80, 0x1a, 0x00, 0x00, + 0x82, 0x90, 0x41, 0x4c, 0x00, 0x00, + 0x08, 0xa4, 0x34, 0x12, 0x00, 0x00, + 0x90, 0x48, 0x88, 0xc8, 0x00, 0x00, + 0x9a, 0xd4, 0x6a, 0x36, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_21[126] = { + 0xc0, 0xa0, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x56, 0x21, 0x44, 0x00, 0x00, + 0x74, 0x40, 0x02, 0x4a, 0x00, 0x00, + 0x00, 0x9c, 0x16, 0x84, 0x00, 0x00, + 0x01, 0x2d, 0xb0, 0x40, 0x00, 0x00, + 0x44, 0x93, 0x05, 0x18, 0x00, 0x00, + 0x88, 0x50, 0x48, 0x94, 0x00, 0x00, + 0x20, 0xa4, 0x70, 0x30, 0x00, 0x00, + 0xaa, 0x04, 0x54, 0x4a, 0x00, 0x00, + 0x02, 0x63, 0x09, 0x24, 0x00, 0x00, + 0x62, 0x22, 0xaa, 0xaa, 0x00, 0x00, + 0xf1, 0x10, 0x54, 0x44, 0x00, 0x00, + 0x10, 0x0e, 0x62, 0x22, 0x00, 0x00, + 0x10, 0xb1, 0x06, 0x84, 0x00, 0x00, + 0x24, 0x24, 0x0d, 0x30, 0x00, 0x00, + 0x01, 0x12, 0x81, 0xc2, 0x00, 0x00, + 0x00, 0xc4, 0x58, 0x88, 0x00, 0x00, + 0x04, 0xa3, 0xb0, 0x50, 0x00, 0x00, + 0x02, 0x59, 0x25, 0x02, 0x00, 0x00, + 0x2b, 0x01, 0x08, 0x64, 0x00, 0x00, + 0x98, 0x40, 0xd0, 0x18, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_22[132] = { + 0x62, 0x22, 0xaa, 0xaa, 0x00, 0x00, + 0xf1, 0x10, 0x54, 0x44, 0x00, 0x00, + 0x10, 0x0e, 0x62, 0x22, 0x00, 0x00, + 0x10, 0xb1, 0x06, 0x84, 0x00, 0x00, + 0x24, 0x24, 0x0d, 0x30, 0x00, 0x00, + 0x01, 0x12, 0x81, 0xc2, 0x00, 0x00, + 0x00, 0xc4, 0x58, 0x88, 0x00, 0x00, + 0x04, 0xa3, 0xb0, 0x50, 0x00, 0x00, + 0x02, 0x59, 0x25, 0x02, 0x00, 0x00, + 0x2b, 0x01, 0x08, 0x64, 0x00, 0x00, + 0x98, 0x40, 0xd0, 0x18, 0x00, 0x00, + 0xc0, 0xa0, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x56, 0x21, 0x44, 0x00, 0x00, + 0x74, 0x40, 0x02, 0x4a, 0x00, 0x00, + 0x00, 0x9c, 0x16, 0x84, 0x00, 0x00, + 0x01, 0x2d, 0xb0, 0x40, 0x00, 0x00, + 0x44, 0x93, 0x05, 0x18, 0x00, 0x00, + 0x88, 0x50, 0x48, 0x94, 0x00, 0x00, + 0x20, 0xa4, 0x70, 0x30, 0x00, 0x00, + 0xaa, 0x04, 0x54, 0x4a, 0x00, 0x00, + 0x02, 0x63, 0x09, 0x24, 0x00, 0x00, + 0x32, 0x23, 0x73, 0x8e, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_23[138] = { + 0x62, 0x22, 0xaa, 0xaa, 0x00, 0x00, + 0xf1, 0x10, 0x54, 0x44, 0x00, 0x00, + 0x10, 0x0e, 0x62, 0x22, 0x00, 0x00, + 0x10, 0xb1, 0x06, 0x84, 0x00, 0x00, + 0x24, 0x24, 0x0d, 0x30, 0x00, 0x00, + 0x01, 0x12, 0x81, 0xc2, 0x00, 0x00, + 0x00, 0xc4, 0x58, 0x88, 0x00, 0x00, + 0x04, 0xa3, 0xb0, 0x50, 0x00, 0x00, + 0x02, 0x59, 0x25, 0x02, 0x00, 0x00, + 0x2b, 0x01, 0x08, 0x64, 0x00, 0x00, + 0x98, 0x40, 0xd0, 0x18, 0x00, 0x00, + 0x88, 0x91, 0x08, 0x62, 0x00, 0x00, + 0x40, 0x54, 0x31, 0x44, 0x00, 0x00, + 0x82, 0x62, 0x9c, 0x02, 0x00, 0x00, + 0x21, 0xa4, 0x89, 0x90, 0x00, 0x00, + 0x10, 0x64, 0x1d, 0x20, 0x00, 0x00, + 0x44, 0x0a, 0x41, 0x98, 0x00, 0x00, + 0x10, 0xc9, 0x26, 0x80, 0x00, 0x00, + 0x4d, 0x2a, 0x5a, 0x20, 0x00, 0x00, + 0x38, 0x02, 0x62, 0x88, 0x00, 0x00, + 0x17, 0x49, 0x80, 0x46, 0x00, 0x00, + 0x90, 0x84, 0x22, 0x4a, 0x00, 0x00, + 0x72, 0x15, 0xd1, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_24[144] = { + 0x88, 0x91, 0x08, 0x62, 0x00, 0x00, + 0x40, 0x54, 0x31, 0x44, 0x00, 0x00, + 0x82, 0x62, 0x9c, 0x02, 0x00, 0x00, + 0x21, 0xa4, 0x89, 0x90, 0x00, 0x00, + 0x10, 0x64, 0x1d, 0x20, 0x00, 0x00, + 0x44, 0x0a, 0x41, 0x98, 0x00, 0x00, + 0x10, 0xc9, 0x26, 0x80, 0x00, 0x00, + 0x4d, 0x2a, 0x5a, 0x20, 0x00, 0x00, + 0x38, 0x02, 0x62, 0x88, 0x00, 0x00, + 0x17, 0x49, 0x80, 0x46, 0x00, 0x00, + 0x90, 0x84, 0x22, 0x4a, 0x00, 0x00, + 0x72, 0x15, 0xd1, 0x00, 0x00, 0x00, + 0x62, 0x22, 0xaa, 0xaa, 0x00, 0x00, + 0xf1, 0x10, 0x54, 0x44, 0x00, 0x00, + 0x10, 0x0e, 0x62, 0x22, 0x00, 0x00, + 0x10, 0xb1, 0x06, 0x84, 0x00, 0x00, + 0x24, 0x24, 0x0d, 0x30, 0x00, 0x00, + 0x01, 0x12, 0x81, 0xc2, 0x00, 0x00, + 0x00, 0xc4, 0x58, 0x88, 0x00, 0x00, + 0x04, 0xa3, 0xb0, 0x50, 0x00, 0x00, + 0x02, 0x59, 0x25, 0x02, 0x00, 0x00, + 0x2b, 0x01, 0x08, 0x64, 0x00, 0x00, + 0x98, 0x40, 0xd0, 0x18, 0x00, 0x00, + 0xf0, 0xdf, 0x91, 0xb6, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_25[150] = { + 0x88, 0x91, 0x08, 0x62, 0x00, 0x00, + 0x40, 0x54, 0x31, 0x44, 0x00, 0x00, + 0x82, 0x62, 0x9c, 0x02, 0x00, 0x00, + 0x21, 0xa4, 0x89, 0x90, 0x00, 0x00, + 0x10, 0x64, 0x1d, 0x20, 0x00, 0x00, + 0x44, 0x0a, 0x41, 0x98, 0x00, 0x00, + 0x10, 0xc9, 0x26, 0x80, 0x00, 0x00, + 0x4d, 0x2a, 0x5a, 0x20, 0x00, 0x00, + 0x38, 0x02, 0x62, 0x88, 0x00, 0x00, + 0x17, 0x49, 0x80, 0x46, 0x00, 0x00, + 0x90, 0x84, 0x22, 0x4a, 0x00, 0x00, + 0x72, 0x15, 0xd1, 0x00, 0x00, 0x00, + 0x62, 0xa2, 0x8a, 0x2a, 0x00, 0x00, + 0x34, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x40, 0x4b, 0x2c, 0x18, 0x00, 0x00, + 0xc4, 0x04, 0x18, 0xa0, 0x00, 0x00, + 0x08, 0x60, 0xc4, 0x08, 0x00, 0x00, + 0x94, 0x12, 0x92, 0x0c, 0x00, 0x00, + 0x88, 0xc0, 0x23, 0x04, 0x00, 0x00, + 0x21, 0x32, 0x24, 0x70, 0x00, 0x00, + 0xc1, 0x40, 0x80, 0xe2, 0x00, 0x00, + 0x10, 0x69, 0x51, 0x14, 0x00, 0x00, + 0x06, 0x90, 0x11, 0x42, 0x00, 0x00, + 0x59, 0x01, 0x41, 0x80, 0x00, 0x00, + 0x0a, 0x0d, 0x8a, 0x20, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_26[156] = { + 0x62, 0xa2, 0x8a, 0x2a, 0x00, 0x00, + 0x34, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x40, 0x4b, 0x2c, 0x18, 0x00, 0x00, + 0xc4, 0x04, 0x18, 0xa0, 0x00, 0x00, + 0x08, 0x60, 0xc4, 0x08, 0x00, 0x00, + 0x94, 0x12, 0x92, 0x0c, 0x00, 0x00, + 0x88, 0xc0, 0x23, 0x04, 0x00, 0x00, + 0x21, 0x32, 0x24, 0x70, 0x00, 0x00, + 0xc1, 0x40, 0x80, 0xe2, 0x00, 0x00, + 0x10, 0x69, 0x51, 0x14, 0x00, 0x00, + 0x06, 0x90, 0x11, 0x42, 0x00, 0x00, + 0x59, 0x01, 0x41, 0x80, 0x00, 0x00, + 0x0a, 0x0d, 0x8a, 0x20, 0x00, 0x00, + 0x88, 0x91, 0x08, 0x62, 0x00, 0x00, + 0x40, 0x54, 0x31, 0x44, 0x00, 0x00, + 0x82, 0x62, 0x9c, 0x02, 0x00, 0x00, + 0x21, 0xa4, 0x89, 0x90, 0x00, 0x00, + 0x10, 0x64, 0x1d, 0x20, 0x00, 0x00, + 0x44, 0x0a, 0x41, 0x98, 0x00, 0x00, + 0x10, 0xc9, 0x26, 0x80, 0x00, 0x00, + 0x4d, 0x2a, 0x5a, 0x20, 0x00, 0x00, + 0x38, 0x02, 0x62, 0x88, 0x00, 0x00, + 0x17, 0x49, 0x80, 0x46, 0x00, 0x00, + 0x90, 0x84, 0x22, 0x4a, 0x00, 0x00, + 0x72, 0x15, 0xd1, 0x00, 0x00, 0x00, + 0xc5, 0x75, 0x48, 0xba, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_27[162] = { + 0x62, 0xa2, 0x8a, 0x2a, 0x00, 0x00, + 0x34, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x40, 0x4b, 0x2c, 0x18, 0x00, 0x00, + 0xc4, 0x04, 0x18, 0xa0, 0x00, 0x00, + 0x08, 0x60, 0xc4, 0x08, 0x00, 0x00, + 0x94, 0x12, 0x92, 0x0c, 0x00, 0x00, + 0x88, 0xc0, 0x23, 0x04, 0x00, 0x00, + 0x21, 0x32, 0x24, 0x70, 0x00, 0x00, + 0xc1, 0x40, 0x80, 0xe2, 0x00, 0x00, + 0x10, 0x69, 0x51, 0x14, 0x00, 0x00, + 0x06, 0x90, 0x11, 0x42, 0x00, 0x00, + 0x59, 0x01, 0x41, 0x80, 0x00, 0x00, + 0x0a, 0x0d, 0x8a, 0x20, 0x00, 0x00, + 0x40, 0x82, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x54, 0x44, 0x14, 0x00, 0x00, + 0x88, 0x13, 0x09, 0xa0, 0x00, 0x00, + 0xc0, 0x10, 0x19, 0x14, 0x00, 0x00, + 0x80, 0xa0, 0x30, 0x0c, 0x00, 0x00, + 0x01, 0x22, 0x60, 0x06, 0x00, 0x00, + 0x40, 0x2c, 0xc2, 0x10, 0x00, 0x00, + 0x22, 0x02, 0x80, 0x22, 0x00, 0x00, + 0x90, 0x04, 0x20, 0x58, 0x00, 0x00, + 0x12, 0x40, 0x12, 0xc0, 0x00, 0x00, + 0x5d, 0x00, 0x01, 0x28, 0x00, 0x00, + 0x20, 0x54, 0xa4, 0x80, 0x00, 0x00, + 0x86, 0x09, 0x48, 0x48, 0x00, 0x00, + 0x28, 0x89, 0x05, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_28[168] = { + 0x40, 0x82, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x54, 0x44, 0x14, 0x00, 0x00, + 0x88, 0x13, 0x09, 0xa0, 0x00, 0x00, + 0xc0, 0x10, 0x19, 0x14, 0x00, 0x00, + 0x80, 0xa0, 0x30, 0x0c, 0x00, 0x00, + 0x01, 0x22, 0x60, 0x06, 0x00, 0x00, + 0x40, 0x2c, 0xc2, 0x10, 0x00, 0x00, + 0x22, 0x02, 0x80, 0x22, 0x00, 0x00, + 0x90, 0x04, 0x20, 0x58, 0x00, 0x00, + 0x12, 0x40, 0x12, 0xc0, 0x00, 0x00, + 0x5d, 0x00, 0x01, 0x28, 0x00, 0x00, + 0x20, 0x54, 0xa4, 0x80, 0x00, 0x00, + 0x86, 0x09, 0x48, 0x48, 0x00, 0x00, + 0x28, 0x89, 0x05, 0x10, 0x00, 0x00, + 0x62, 0xa2, 0x8a, 0x2a, 0x00, 0x00, + 0x34, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x40, 0x4b, 0x2c, 0x18, 0x00, 0x00, + 0xc4, 0x04, 0x18, 0xa0, 0x00, 0x00, + 0x08, 0x60, 0xc4, 0x08, 0x00, 0x00, + 0x94, 0x12, 0x92, 0x0c, 0x00, 0x00, + 0x88, 0xc0, 0x23, 0x04, 0x00, 0x00, + 0x21, 0x32, 0x24, 0x70, 0x00, 0x00, + 0xc1, 0x40, 0x80, 0xe2, 0x00, 0x00, + 0x10, 0x69, 0x51, 0x14, 0x00, 0x00, + 0x06, 0x90, 0x11, 0x42, 0x00, 0x00, + 0x59, 0x01, 0x41, 0x80, 0x00, 0x00, + 0x0a, 0x0d, 0x8a, 0x20, 0x00, 0x00, + 0xbc, 0x0d, 0xca, 0x28, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_29[174] = { + 0x40, 0x82, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x54, 0x44, 0x14, 0x00, 0x00, + 0x88, 0x13, 0x09, 0xa0, 0x00, 0x00, + 0xc0, 0x10, 0x19, 0x14, 0x00, 0x00, + 0x80, 0xa0, 0x30, 0x0c, 0x00, 0x00, + 0x01, 0x22, 0x60, 0x06, 0x00, 0x00, + 0x40, 0x2c, 0xc2, 0x10, 0x00, 0x00, + 0x22, 0x02, 0x80, 0x22, 0x00, 0x00, + 0x90, 0x04, 0x20, 0x58, 0x00, 0x00, + 0x12, 0x40, 0x12, 0xc0, 0x00, 0x00, + 0x5d, 0x00, 0x01, 0x28, 0x00, 0x00, + 0x20, 0x54, 0xa4, 0x80, 0x00, 0x00, + 0x86, 0x09, 0x48, 0x48, 0x00, 0x00, + 0x28, 0x89, 0x05, 0x10, 0x00, 0x00, + 0x62, 0x22, 0xaa, 0x22, 0x00, 0x00, + 0x31, 0x10, 0x44, 0x44, 0x00, 0x00, + 0x58, 0x00, 0x22, 0x22, 0x00, 0x00, + 0x01, 0x13, 0x00, 0x8a, 0x00, 0x00, + 0x88, 0x20, 0x40, 0x34, 0x00, 0x00, + 0x44, 0x02, 0x10, 0xd0, 0x00, 0x00, + 0x29, 0x04, 0x45, 0x08, 0x00, 0x00, + 0x82, 0xa0, 0x90, 0x12, 0x00, 0x00, + 0x0a, 0x1a, 0x0e, 0x02, 0x00, 0x00, + 0x11, 0xe1, 0x28, 0x40, 0x00, 0x00, + 0x84, 0x05, 0x04, 0x0c, 0x00, 0x00, + 0x86, 0x40, 0xc0, 0x90, 0x00, 0x00, + 0x00, 0x87, 0x13, 0x00, 0x00, 0x00, + 0x44, 0x48, 0x01, 0x1c, 0x00, 0x00, + 0x10, 0x98, 0x30, 0x44, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_3[18] = { + 0xac, 0x93, 0x5a, 0x5a, 0x00, 0x00, + 0x55, 0x4a, 0xec, 0x6c, 0x00, 0x00, + 0x43, 0x36, 0x4d, 0xb6, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_30[180] = { + 0x62, 0x22, 0xaa, 0x22, 0x00, 0x00, + 0x31, 0x10, 0x44, 0x44, 0x00, 0x00, + 0x58, 0x00, 0x22, 0x22, 0x00, 0x00, + 0x01, 0x13, 0x00, 0x8a, 0x00, 0x00, + 0x88, 0x20, 0x40, 0x34, 0x00, 0x00, + 0x44, 0x02, 0x10, 0xd0, 0x00, 0x00, + 0x29, 0x04, 0x45, 0x08, 0x00, 0x00, + 0x82, 0xa0, 0x90, 0x12, 0x00, 0x00, + 0x0a, 0x1a, 0x0e, 0x02, 0x00, 0x00, + 0x11, 0xe1, 0x28, 0x40, 0x00, 0x00, + 0x84, 0x05, 0x04, 0x0c, 0x00, 0x00, + 0x86, 0x40, 0xc0, 0x90, 0x00, 0x00, + 0x00, 0x87, 0x13, 0x00, 0x00, 0x00, + 0x44, 0x48, 0x01, 0x1c, 0x00, 0x00, + 0x10, 0x98, 0x30, 0x44, 0x00, 0x00, + 0x40, 0x82, 0x8a, 0xa2, 0x00, 0x00, + 0x15, 0x54, 0x44, 0x14, 0x00, 0x00, + 0x88, 0x13, 0x09, 0xa0, 0x00, 0x00, + 0xc0, 0x10, 0x19, 0x14, 0x00, 0x00, + 0x80, 0xa0, 0x30, 0x0c, 0x00, 0x00, + 0x01, 0x22, 0x60, 0x06, 0x00, 0x00, + 0x40, 0x2c, 0xc2, 0x10, 0x00, 0x00, + 0x22, 0x02, 0x80, 0x22, 0x00, 0x00, + 0x90, 0x04, 0x20, 0x58, 0x00, 0x00, + 0x12, 0x40, 0x12, 0xc0, 0x00, 0x00, + 0x5d, 0x00, 0x01, 0x28, 0x00, 0x00, + 0x20, 0x54, 0xa4, 0x80, 0x00, 0x00, + 0x86, 0x09, 0x48, 0x48, 0x00, 0x00, + 0x28, 0x89, 0x05, 0x10, 0x00, 0x00, + 0xe1, 0x4f, 0xe0, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_31[186] = { + 0x62, 0x22, 0xaa, 0x22, 0x00, 0x00, + 0x31, 0x10, 0x44, 0x44, 0x00, 0x00, + 0x58, 0x00, 0x22, 0x22, 0x00, 0x00, + 0x01, 0x13, 0x00, 0x8a, 0x00, 0x00, + 0x88, 0x20, 0x40, 0x34, 0x00, 0x00, + 0x44, 0x02, 0x10, 0xd0, 0x00, 0x00, + 0x29, 0x04, 0x45, 0x08, 0x00, 0x00, + 0x82, 0xa0, 0x90, 0x12, 0x00, 0x00, + 0x0a, 0x1a, 0x0e, 0x02, 0x00, 0x00, + 0x11, 0xe1, 0x28, 0x40, 0x00, 0x00, + 0x84, 0x05, 0x04, 0x0c, 0x00, 0x00, + 0x86, 0x40, 0xc0, 0x90, 0x00, 0x00, + 0x00, 0x87, 0x13, 0x00, 0x00, 0x00, + 0x44, 0x48, 0x01, 0x1c, 0x00, 0x00, + 0x10, 0x98, 0x30, 0x44, 0x00, 0x00, + 0x62, 0x23, 0x48, 0x20, 0x00, 0x00, + 0x31, 0x10, 0x02, 0x54, 0x00, 0x00, + 0x58, 0x00, 0x0c, 0x84, 0x00, 0x00, + 0x01, 0x12, 0x10, 0xd0, 0x00, 0x00, + 0x88, 0x21, 0x03, 0x20, 0x00, 0x00, + 0x44, 0x02, 0x01, 0xe0, 0x00, 0x00, + 0x29, 0x04, 0xa0, 0x0a, 0x00, 0x00, + 0x82, 0xa0, 0x40, 0xa2, 0x00, 0x00, + 0x0a, 0x1a, 0x86, 0x10, 0x00, 0x00, + 0x11, 0xe0, 0xd1, 0x00, 0x00, 0x00, + 0x84, 0x05, 0x00, 0x16, 0x00, 0x00, + 0x86, 0x40, 0x20, 0x98, 0x00, 0x00, + 0x00, 0x86, 0x24, 0x60, 0x00, 0x00, + 0x44, 0x48, 0x81, 0x0a, 0x00, 0x00, + 0x10, 0x98, 0x1c, 0x08, 0x00, 0x00, + 0x87, 0x74, 0x30, 0x24, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_4[24] = { + 0x25, 0xaa, 0xaa, 0xaa, 0x00, 0x00, + 0x95, 0x55, 0x55, 0x54, 0x00, 0x00, + 0x1a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, + 0x43, 0xd5, 0x95, 0x94, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_5[30] = { + 0x64, 0xa2, 0xaa, 0xaa, 0x00, 0x00, + 0x25, 0x54, 0x54, 0x54, 0x00, 0x00, + 0x49, 0x68, 0x48, 0x4a, 0x00, 0x00, + 0x53, 0x91, 0x09, 0x90, 0x00, 0x00, + 0x8e, 0x30, 0x21, 0x6c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_6[36] = { + 0x62, 0x8a, 0xa2, 0xa2, 0x00, 0x00, + 0x15, 0x54, 0x14, 0x54, 0x00, 0x00, + 0x4c, 0x47, 0x44, 0x2a, 0x00, 0x00, + 0x52, 0x95, 0x08, 0x94, 0x00, 0x00, + 0x23, 0x64, 0x61, 0x24, 0x00, 0x00, + 0x8a, 0x58, 0x09, 0x58, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_7[42] = { + 0x62, 0xa2, 0x8a, 0xa2, 0x00, 0x00, + 0xb1, 0x14, 0x44, 0x54, 0x00, 0x00, + 0x18, 0x6b, 0x22, 0x22, 0x00, 0x00, + 0x44, 0xd4, 0x5c, 0x10, 0x00, 0x00, + 0x13, 0x64, 0x90, 0x68, 0x00, 0x00, + 0x49, 0x1b, 0x20, 0x52, 0x00, 0x00, + 0x86, 0x8c, 0x13, 0x0c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_8[48] = { + 0x90, 0x22, 0x40, 0xa8, 0x00, 0x00, + 0x09, 0x50, 0x31, 0x10, 0x00, 0x00, + 0x00, 0x6b, 0x08, 0x0e, 0x00, 0x00, + 0x20, 0x34, 0xc0, 0x90, 0x00, 0x00, + 0x14, 0x44, 0x25, 0x04, 0x00, 0x00, + 0xc2, 0x11, 0x02, 0x82, 0x00, 0x00, + 0x00, 0xc6, 0x80, 0xc4, 0x00, 0x00, + 0x65, 0x80, 0x2c, 0x60, 0x00, 0x00 +}; + +const uint8_t kMaskRandom31_9[54] = { + 0x62, 0x22, 0xaa, 0xa2, 0x00, 0x00, + 0x24, 0x44, 0x44, 0x54, 0x00, 0x00, + 0xc0, 0x50, 0x0b, 0x0a, 0x00, 0x00, + 0x03, 0x0c, 0x12, 0x94, 0x00, 0x00, + 0x16, 0x29, 0x08, 0x64, 0x00, 0x00, + 0x89, 0x01, 0x80, 0x1a, 0x00, 0x00, + 0x82, 0x90, 0x41, 0x4c, 0x00, 0x00, + 0x08, 0xa4, 0x34, 0x12, 0x00, 0x00, + 0x90, 0x48, 0x88, 0xc8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_10[60] = { + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x10, 0xa2, 0x10, 0xa2, 0x00, 0x00, + 0x01, 0x25, 0x01, 0x25, 0x00, 0x00, + 0x0b, 0x42, 0x0b, 0x42, 0x00, 0x00, + 0xd8, 0x20, 0xd8, 0x20, 0x00, 0x00, + 0x82, 0x8c, 0x82, 0x8c, 0x00, 0x00, + 0x24, 0x4a, 0x24, 0x4a, 0x00, 0x00, + 0x38, 0x18, 0x38, 0x18, 0x00, 0x00, + 0x2a, 0x25, 0x2a, 0x25, 0x00, 0x00, + 0x84, 0x92, 0x84, 0x92, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_11[66] = { + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x2a, 0x22, 0x2a, 0x22, 0x00, 0x00, + 0x31, 0x11, 0x31, 0x11, 0x00, 0x00, + 0x83, 0x42, 0x83, 0x42, 0x00, 0x00, + 0x06, 0x98, 0x06, 0x98, 0x00, 0x00, + 0x40, 0xe1, 0x40, 0xe1, 0x00, 0x00, + 0x2c, 0x44, 0x2c, 0x44, 0x00, 0x00, + 0xd8, 0x28, 0xd8, 0x28, 0x00, 0x00, + 0x92, 0x81, 0x92, 0x81, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0x68, 0x0c, 0x68, 0x0c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_12[72] = { + 0x84, 0x31, 0x84, 0x31, 0x00, 0x00, + 0x18, 0xa2, 0x18, 0xa2, 0x00, 0x00, + 0x4e, 0x01, 0x4e, 0x01, 0x00, 0x00, + 0x44, 0xc8, 0x44, 0xc8, 0x00, 0x00, + 0x0e, 0x90, 0x0e, 0x90, 0x00, 0x00, + 0x20, 0xcc, 0x20, 0xcc, 0x00, 0x00, + 0x93, 0x40, 0x93, 0x40, 0x00, 0x00, + 0x2d, 0x10, 0x2d, 0x10, 0x00, 0x00, + 0x31, 0x44, 0x31, 0x44, 0x00, 0x00, + 0xc0, 0x23, 0xc0, 0x23, 0x00, 0x00, + 0x11, 0x25, 0x11, 0x25, 0x00, 0x00, + 0xe8, 0x80, 0xe8, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_13[78] = { + 0x45, 0x15, 0x45, 0x15, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x96, 0x0c, 0x96, 0x0c, 0x00, 0x00, + 0x0c, 0x50, 0x0c, 0x50, 0x00, 0x00, + 0x62, 0x04, 0x62, 0x04, 0x00, 0x00, + 0x49, 0x06, 0x49, 0x06, 0x00, 0x00, + 0x11, 0x82, 0x11, 0x82, 0x00, 0x00, + 0x12, 0x38, 0x12, 0x38, 0x00, 0x00, + 0x40, 0x71, 0x40, 0x71, 0x00, 0x00, + 0xa8, 0x8a, 0xa8, 0x8a, 0x00, 0x00, + 0x08, 0xa1, 0x08, 0xa1, 0x00, 0x00, + 0xa0, 0xc0, 0xa0, 0xc0, 0x00, 0x00, + 0xc5, 0x10, 0xc5, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_14[84] = { + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x22, 0x0a, 0x22, 0x0a, 0x00, 0x00, + 0x84, 0xd0, 0x84, 0xd0, 0x00, 0x00, + 0x0c, 0x8a, 0x0c, 0x8a, 0x00, 0x00, + 0x18, 0x06, 0x18, 0x06, 0x00, 0x00, + 0x30, 0x03, 0x30, 0x03, 0x00, 0x00, + 0x61, 0x08, 0x61, 0x08, 0x00, 0x00, + 0x40, 0x11, 0x40, 0x11, 0x00, 0x00, + 0x10, 0x2c, 0x10, 0x2c, 0x00, 0x00, + 0x09, 0x60, 0x09, 0x60, 0x00, 0x00, + 0x00, 0x94, 0x00, 0x94, 0x00, 0x00, + 0x52, 0x40, 0x52, 0x40, 0x00, 0x00, + 0xa4, 0x24, 0xa4, 0x24, 0x00, 0x00, + 0x82, 0x88, 0x82, 0x88, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_15[90] = { + 0x55, 0x11, 0x55, 0x11, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, + 0x80, 0x45, 0x80, 0x45, 0x00, 0x00, + 0x20, 0x1a, 0x20, 0x1a, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x22, 0x84, 0x22, 0x84, 0x00, 0x00, + 0x48, 0x09, 0x48, 0x09, 0x00, 0x00, + 0x07, 0x01, 0x07, 0x01, 0x00, 0x00, + 0x94, 0x20, 0x94, 0x20, 0x00, 0x00, + 0x82, 0x06, 0x82, 0x06, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x89, 0x80, 0x89, 0x80, 0x00, 0x00, + 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x00, + 0x18, 0x22, 0x18, 0x22, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_16[96] = { + 0xa4, 0x10, 0xa4, 0x10, 0x00, 0x00, + 0x01, 0x2a, 0x01, 0x2a, 0x00, 0x00, + 0x06, 0x42, 0x06, 0x42, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x81, 0x90, 0x81, 0x90, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, + 0x50, 0x05, 0x50, 0x05, 0x00, 0x00, + 0x20, 0x51, 0x20, 0x51, 0x00, 0x00, + 0x43, 0x08, 0x43, 0x08, 0x00, 0x00, + 0x68, 0x80, 0x68, 0x80, 0x00, 0x00, + 0x80, 0x0b, 0x80, 0x0b, 0x00, 0x00, + 0x10, 0x4c, 0x10, 0x4c, 0x00, 0x00, + 0x12, 0x30, 0x12, 0x30, 0x00, 0x00, + 0x40, 0x85, 0x40, 0x85, 0x00, 0x00, + 0x0e, 0x04, 0x0e, 0x04, 0x00, 0x00, + 0x18, 0x12, 0x18, 0x12, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_17[102] = { + 0x20, 0x54, 0x20, 0x54, 0x00, 0x00, + 0x18, 0x88, 0x18, 0x88, 0x00, 0x00, + 0x84, 0x07, 0x84, 0x07, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x12, 0x82, 0x12, 0x82, 0x00, 0x00, + 0x81, 0x41, 0x81, 0x41, 0x00, 0x00, + 0x40, 0x62, 0x40, 0x62, 0x00, 0x00, + 0x16, 0x30, 0x16, 0x30, 0x00, 0x00, + 0x55, 0x51, 0x55, 0x51, 0x00, 0x00, + 0x22, 0x2a, 0x22, 0x2a, 0x00, 0x00, + 0x05, 0x85, 0x05, 0x85, 0x00, 0x00, + 0x09, 0x4a, 0x09, 0x4a, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x00, + 0x20, 0xa6, 0x20, 0xa6, 0x00, 0x00, + 0x1a, 0x09, 0x1a, 0x09, 0x00, 0x00, + 0x44, 0x64, 0x44, 0x64, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_18[108] = { + 0x55, 0x51, 0x55, 0x51, 0x00, 0x00, + 0x22, 0x2a, 0x22, 0x2a, 0x00, 0x00, + 0x05, 0x85, 0x05, 0x85, 0x00, 0x00, + 0x09, 0x4a, 0x09, 0x4a, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x00, + 0x20, 0xa6, 0x20, 0xa6, 0x00, 0x00, + 0x1a, 0x09, 0x1a, 0x09, 0x00, 0x00, + 0x44, 0x64, 0x44, 0x64, 0x00, 0x00, + 0x20, 0x54, 0x20, 0x54, 0x00, 0x00, + 0x18, 0x88, 0x18, 0x88, 0x00, 0x00, + 0x84, 0x07, 0x84, 0x07, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x12, 0x82, 0x12, 0x82, 0x00, 0x00, + 0x81, 0x41, 0x81, 0x41, 0x00, 0x00, + 0x40, 0x62, 0x40, 0x62, 0x00, 0x00, + 0x16, 0x30, 0x16, 0x30, 0x00, 0x00, + 0x1e, 0xb2, 0xd8, 0x53, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_19[114] = { + 0x55, 0x51, 0x55, 0x51, 0x00, 0x00, + 0x22, 0x2a, 0x22, 0x2a, 0x00, 0x00, + 0x05, 0x85, 0x05, 0x85, 0x00, 0x00, + 0x09, 0x4a, 0x09, 0x4a, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x00, + 0x20, 0xa6, 0x20, 0xa6, 0x00, 0x00, + 0x1a, 0x09, 0x1a, 0x09, 0x00, 0x00, + 0x44, 0x64, 0x44, 0x64, 0x00, 0x00, + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x10, 0xa2, 0x10, 0xa2, 0x00, 0x00, + 0x01, 0x25, 0x01, 0x25, 0x00, 0x00, + 0x0b, 0x42, 0x0b, 0x42, 0x00, 0x00, + 0xd8, 0x20, 0xd8, 0x20, 0x00, 0x00, + 0x82, 0x8c, 0x82, 0x8c, 0x00, 0x00, + 0x24, 0x4a, 0x24, 0x4a, 0x00, 0x00, + 0x38, 0x18, 0x38, 0x18, 0x00, 0x00, + 0x2a, 0x25, 0x2a, 0x25, 0x00, 0x00, + 0x84, 0x92, 0x84, 0x92, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_2[12] = { + 0xae, 0xae, 0xae, 0xae, 0x00, 0x00, + 0x79, 0x79, 0x79, 0x79, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_20[120] = { + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x10, 0xa2, 0x10, 0xa2, 0x00, 0x00, + 0x01, 0x25, 0x01, 0x25, 0x00, 0x00, + 0x0b, 0x42, 0x0b, 0x42, 0x00, 0x00, + 0xd8, 0x20, 0xd8, 0x20, 0x00, 0x00, + 0x82, 0x8c, 0x82, 0x8c, 0x00, 0x00, + 0x24, 0x4a, 0x24, 0x4a, 0x00, 0x00, + 0x38, 0x18, 0x38, 0x18, 0x00, 0x00, + 0x2a, 0x25, 0x2a, 0x25, 0x00, 0x00, + 0x84, 0x92, 0x84, 0x92, 0x00, 0x00, + 0x55, 0x51, 0x55, 0x51, 0x00, 0x00, + 0x22, 0x2a, 0x22, 0x2a, 0x00, 0x00, + 0x05, 0x85, 0x05, 0x85, 0x00, 0x00, + 0x09, 0x4a, 0x09, 0x4a, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x00, + 0x20, 0xa6, 0x20, 0xa6, 0x00, 0x00, + 0x1a, 0x09, 0x1a, 0x09, 0x00, 0x00, + 0x44, 0x64, 0x44, 0x64, 0x00, 0x00, + 0x96, 0xd3, 0xf6, 0xac, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_21[126] = { + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x10, 0xa2, 0x10, 0xa2, 0x00, 0x00, + 0x01, 0x25, 0x01, 0x25, 0x00, 0x00, + 0x0b, 0x42, 0x0b, 0x42, 0x00, 0x00, + 0xd8, 0x20, 0xd8, 0x20, 0x00, 0x00, + 0x82, 0x8c, 0x82, 0x8c, 0x00, 0x00, + 0x24, 0x4a, 0x24, 0x4a, 0x00, 0x00, + 0x38, 0x18, 0x38, 0x18, 0x00, 0x00, + 0x2a, 0x25, 0x2a, 0x25, 0x00, 0x00, + 0x84, 0x92, 0x84, 0x92, 0x00, 0x00, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x2a, 0x22, 0x2a, 0x22, 0x00, 0x00, + 0x31, 0x11, 0x31, 0x11, 0x00, 0x00, + 0x83, 0x42, 0x83, 0x42, 0x00, 0x00, + 0x06, 0x98, 0x06, 0x98, 0x00, 0x00, + 0x40, 0xe1, 0x40, 0xe1, 0x00, 0x00, + 0x2c, 0x44, 0x2c, 0x44, 0x00, 0x00, + 0xd8, 0x28, 0xd8, 0x28, 0x00, 0x00, + 0x92, 0x81, 0x92, 0x81, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0x68, 0x0c, 0x68, 0x0c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_22[132] = { + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x2a, 0x22, 0x2a, 0x22, 0x00, 0x00, + 0x31, 0x11, 0x31, 0x11, 0x00, 0x00, + 0x83, 0x42, 0x83, 0x42, 0x00, 0x00, + 0x06, 0x98, 0x06, 0x98, 0x00, 0x00, + 0x40, 0xe1, 0x40, 0xe1, 0x00, 0x00, + 0x2c, 0x44, 0x2c, 0x44, 0x00, 0x00, + 0xd8, 0x28, 0xd8, 0x28, 0x00, 0x00, + 0x92, 0x81, 0x92, 0x81, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0x68, 0x0c, 0x68, 0x0c, 0x00, 0x00, + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x10, 0xa2, 0x10, 0xa2, 0x00, 0x00, + 0x01, 0x25, 0x01, 0x25, 0x00, 0x00, + 0x0b, 0x42, 0x0b, 0x42, 0x00, 0x00, + 0xd8, 0x20, 0xd8, 0x20, 0x00, 0x00, + 0x82, 0x8c, 0x82, 0x8c, 0x00, 0x00, + 0x24, 0x4a, 0x24, 0x4a, 0x00, 0x00, + 0x38, 0x18, 0x38, 0x18, 0x00, 0x00, + 0x2a, 0x25, 0x2a, 0x25, 0x00, 0x00, + 0x84, 0x92, 0x84, 0x92, 0x00, 0x00, + 0xeb, 0xb2, 0x22, 0x89, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_23[138] = { + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x2a, 0x22, 0x2a, 0x22, 0x00, 0x00, + 0x31, 0x11, 0x31, 0x11, 0x00, 0x00, + 0x83, 0x42, 0x83, 0x42, 0x00, 0x00, + 0x06, 0x98, 0x06, 0x98, 0x00, 0x00, + 0x40, 0xe1, 0x40, 0xe1, 0x00, 0x00, + 0x2c, 0x44, 0x2c, 0x44, 0x00, 0x00, + 0xd8, 0x28, 0xd8, 0x28, 0x00, 0x00, + 0x92, 0x81, 0x92, 0x81, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0x68, 0x0c, 0x68, 0x0c, 0x00, 0x00, + 0x84, 0x31, 0x84, 0x31, 0x00, 0x00, + 0x18, 0xa2, 0x18, 0xa2, 0x00, 0x00, + 0x4e, 0x01, 0x4e, 0x01, 0x00, 0x00, + 0x44, 0xc8, 0x44, 0xc8, 0x00, 0x00, + 0x0e, 0x90, 0x0e, 0x90, 0x00, 0x00, + 0x20, 0xcc, 0x20, 0xcc, 0x00, 0x00, + 0x93, 0x40, 0x93, 0x40, 0x00, 0x00, + 0x2d, 0x10, 0x2d, 0x10, 0x00, 0x00, + 0x31, 0x44, 0x31, 0x44, 0x00, 0x00, + 0xc0, 0x23, 0xc0, 0x23, 0x00, 0x00, + 0x11, 0x25, 0x11, 0x25, 0x00, 0x00, + 0xe8, 0x80, 0xe8, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_24[144] = { + 0x84, 0x31, 0x84, 0x31, 0x00, 0x00, + 0x18, 0xa2, 0x18, 0xa2, 0x00, 0x00, + 0x4e, 0x01, 0x4e, 0x01, 0x00, 0x00, + 0x44, 0xc8, 0x44, 0xc8, 0x00, 0x00, + 0x0e, 0x90, 0x0e, 0x90, 0x00, 0x00, + 0x20, 0xcc, 0x20, 0xcc, 0x00, 0x00, + 0x93, 0x40, 0x93, 0x40, 0x00, 0x00, + 0x2d, 0x10, 0x2d, 0x10, 0x00, 0x00, + 0x31, 0x44, 0x31, 0x44, 0x00, 0x00, + 0xc0, 0x23, 0xc0, 0x23, 0x00, 0x00, + 0x11, 0x25, 0x11, 0x25, 0x00, 0x00, + 0xe8, 0x80, 0xe8, 0x80, 0x00, 0x00, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x2a, 0x22, 0x2a, 0x22, 0x00, 0x00, + 0x31, 0x11, 0x31, 0x11, 0x00, 0x00, + 0x83, 0x42, 0x83, 0x42, 0x00, 0x00, + 0x06, 0x98, 0x06, 0x98, 0x00, 0x00, + 0x40, 0xe1, 0x40, 0xe1, 0x00, 0x00, + 0x2c, 0x44, 0x2c, 0x44, 0x00, 0x00, + 0xd8, 0x28, 0xd8, 0x28, 0x00, 0x00, + 0x92, 0x81, 0x92, 0x81, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0x68, 0x0c, 0x68, 0x0c, 0x00, 0x00, + 0xf3, 0x5a, 0x2f, 0x5d, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_25[150] = { + 0x84, 0x31, 0x84, 0x31, 0x00, 0x00, + 0x18, 0xa2, 0x18, 0xa2, 0x00, 0x00, + 0x4e, 0x01, 0x4e, 0x01, 0x00, 0x00, + 0x44, 0xc8, 0x44, 0xc8, 0x00, 0x00, + 0x0e, 0x90, 0x0e, 0x90, 0x00, 0x00, + 0x20, 0xcc, 0x20, 0xcc, 0x00, 0x00, + 0x93, 0x40, 0x93, 0x40, 0x00, 0x00, + 0x2d, 0x10, 0x2d, 0x10, 0x00, 0x00, + 0x31, 0x44, 0x31, 0x44, 0x00, 0x00, + 0xc0, 0x23, 0xc0, 0x23, 0x00, 0x00, + 0x11, 0x25, 0x11, 0x25, 0x00, 0x00, + 0xe8, 0x80, 0xe8, 0x80, 0x00, 0x00, + 0x45, 0x15, 0x45, 0x15, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x96, 0x0c, 0x96, 0x0c, 0x00, 0x00, + 0x0c, 0x50, 0x0c, 0x50, 0x00, 0x00, + 0x62, 0x04, 0x62, 0x04, 0x00, 0x00, + 0x49, 0x06, 0x49, 0x06, 0x00, 0x00, + 0x11, 0x82, 0x11, 0x82, 0x00, 0x00, + 0x12, 0x38, 0x12, 0x38, 0x00, 0x00, + 0x40, 0x71, 0x40, 0x71, 0x00, 0x00, + 0xa8, 0x8a, 0xa8, 0x8a, 0x00, 0x00, + 0x08, 0xa1, 0x08, 0xa1, 0x00, 0x00, + 0xa0, 0xc0, 0xa0, 0xc0, 0x00, 0x00, + 0xc5, 0x10, 0xc5, 0x10, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_26[156] = { + 0x45, 0x15, 0x45, 0x15, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x96, 0x0c, 0x96, 0x0c, 0x00, 0x00, + 0x0c, 0x50, 0x0c, 0x50, 0x00, 0x00, + 0x62, 0x04, 0x62, 0x04, 0x00, 0x00, + 0x49, 0x06, 0x49, 0x06, 0x00, 0x00, + 0x11, 0x82, 0x11, 0x82, 0x00, 0x00, + 0x12, 0x38, 0x12, 0x38, 0x00, 0x00, + 0x40, 0x71, 0x40, 0x71, 0x00, 0x00, + 0xa8, 0x8a, 0xa8, 0x8a, 0x00, 0x00, + 0x08, 0xa1, 0x08, 0xa1, 0x00, 0x00, + 0xa0, 0xc0, 0xa0, 0xc0, 0x00, 0x00, + 0xc5, 0x10, 0xc5, 0x10, 0x00, 0x00, + 0x84, 0x31, 0x84, 0x31, 0x00, 0x00, + 0x18, 0xa2, 0x18, 0xa2, 0x00, 0x00, + 0x4e, 0x01, 0x4e, 0x01, 0x00, 0x00, + 0x44, 0xc8, 0x44, 0xc8, 0x00, 0x00, + 0x0e, 0x90, 0x0e, 0x90, 0x00, 0x00, + 0x20, 0xcc, 0x20, 0xcc, 0x00, 0x00, + 0x93, 0x40, 0x93, 0x40, 0x00, 0x00, + 0x2d, 0x10, 0x2d, 0x10, 0x00, 0x00, + 0x31, 0x44, 0x31, 0x44, 0x00, 0x00, + 0xc0, 0x23, 0xc0, 0x23, 0x00, 0x00, + 0x11, 0x25, 0x11, 0x25, 0x00, 0x00, + 0xe8, 0x80, 0xe8, 0x80, 0x00, 0x00, + 0x52, 0x15, 0x62, 0x0a, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_27[162] = { + 0x45, 0x15, 0x45, 0x15, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x96, 0x0c, 0x96, 0x0c, 0x00, 0x00, + 0x0c, 0x50, 0x0c, 0x50, 0x00, 0x00, + 0x62, 0x04, 0x62, 0x04, 0x00, 0x00, + 0x49, 0x06, 0x49, 0x06, 0x00, 0x00, + 0x11, 0x82, 0x11, 0x82, 0x00, 0x00, + 0x12, 0x38, 0x12, 0x38, 0x00, 0x00, + 0x40, 0x71, 0x40, 0x71, 0x00, 0x00, + 0xa8, 0x8a, 0xa8, 0x8a, 0x00, 0x00, + 0x08, 0xa1, 0x08, 0xa1, 0x00, 0x00, + 0xa0, 0xc0, 0xa0, 0xc0, 0x00, 0x00, + 0xc5, 0x10, 0xc5, 0x10, 0x00, 0x00, + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x22, 0x0a, 0x22, 0x0a, 0x00, 0x00, + 0x84, 0xd0, 0x84, 0xd0, 0x00, 0x00, + 0x0c, 0x8a, 0x0c, 0x8a, 0x00, 0x00, + 0x18, 0x06, 0x18, 0x06, 0x00, 0x00, + 0x30, 0x03, 0x30, 0x03, 0x00, 0x00, + 0x61, 0x08, 0x61, 0x08, 0x00, 0x00, + 0x40, 0x11, 0x40, 0x11, 0x00, 0x00, + 0x10, 0x2c, 0x10, 0x2c, 0x00, 0x00, + 0x09, 0x60, 0x09, 0x60, 0x00, 0x00, + 0x00, 0x94, 0x00, 0x94, 0x00, 0x00, + 0x52, 0x40, 0x52, 0x40, 0x00, 0x00, + 0xa4, 0x24, 0xa4, 0x24, 0x00, 0x00, + 0x82, 0x88, 0x82, 0x88, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_28[168] = { + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x22, 0x0a, 0x22, 0x0a, 0x00, 0x00, + 0x84, 0xd0, 0x84, 0xd0, 0x00, 0x00, + 0x0c, 0x8a, 0x0c, 0x8a, 0x00, 0x00, + 0x18, 0x06, 0x18, 0x06, 0x00, 0x00, + 0x30, 0x03, 0x30, 0x03, 0x00, 0x00, + 0x61, 0x08, 0x61, 0x08, 0x00, 0x00, + 0x40, 0x11, 0x40, 0x11, 0x00, 0x00, + 0x10, 0x2c, 0x10, 0x2c, 0x00, 0x00, + 0x09, 0x60, 0x09, 0x60, 0x00, 0x00, + 0x00, 0x94, 0x00, 0x94, 0x00, 0x00, + 0x52, 0x40, 0x52, 0x40, 0x00, 0x00, + 0xa4, 0x24, 0xa4, 0x24, 0x00, 0x00, + 0x82, 0x88, 0x82, 0x88, 0x00, 0x00, + 0x45, 0x15, 0x45, 0x15, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x96, 0x0c, 0x96, 0x0c, 0x00, 0x00, + 0x0c, 0x50, 0x0c, 0x50, 0x00, 0x00, + 0x62, 0x04, 0x62, 0x04, 0x00, 0x00, + 0x49, 0x06, 0x49, 0x06, 0x00, 0x00, + 0x11, 0x82, 0x11, 0x82, 0x00, 0x00, + 0x12, 0x38, 0x12, 0x38, 0x00, 0x00, + 0x40, 0x71, 0x40, 0x71, 0x00, 0x00, + 0xa8, 0x8a, 0xa8, 0x8a, 0x00, 0x00, + 0x08, 0xa1, 0x08, 0xa1, 0x00, 0x00, + 0xa0, 0xc0, 0xa0, 0xc0, 0x00, 0x00, + 0xc5, 0x10, 0xc5, 0x10, 0x00, 0x00, + 0x7f, 0xe2, 0xbc, 0x01, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_29[174] = { + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x22, 0x0a, 0x22, 0x0a, 0x00, 0x00, + 0x84, 0xd0, 0x84, 0xd0, 0x00, 0x00, + 0x0c, 0x8a, 0x0c, 0x8a, 0x00, 0x00, + 0x18, 0x06, 0x18, 0x06, 0x00, 0x00, + 0x30, 0x03, 0x30, 0x03, 0x00, 0x00, + 0x61, 0x08, 0x61, 0x08, 0x00, 0x00, + 0x40, 0x11, 0x40, 0x11, 0x00, 0x00, + 0x10, 0x2c, 0x10, 0x2c, 0x00, 0x00, + 0x09, 0x60, 0x09, 0x60, 0x00, 0x00, + 0x00, 0x94, 0x00, 0x94, 0x00, 0x00, + 0x52, 0x40, 0x52, 0x40, 0x00, 0x00, + 0xa4, 0x24, 0xa4, 0x24, 0x00, 0x00, + 0x82, 0x88, 0x82, 0x88, 0x00, 0x00, + 0x55, 0x11, 0x55, 0x11, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, + 0x80, 0x45, 0x80, 0x45, 0x00, 0x00, + 0x20, 0x1a, 0x20, 0x1a, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x22, 0x84, 0x22, 0x84, 0x00, 0x00, + 0x48, 0x09, 0x48, 0x09, 0x00, 0x00, + 0x07, 0x01, 0x07, 0x01, 0x00, 0x00, + 0x94, 0x20, 0x94, 0x20, 0x00, 0x00, + 0x82, 0x06, 0x82, 0x06, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x89, 0x80, 0x89, 0x80, 0x00, 0x00, + 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x00, + 0x18, 0x22, 0x18, 0x22, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_3[18] = { + 0xad, 0x2d, 0xad, 0x2d, 0x00, 0x00, + 0x76, 0x36, 0x76, 0x36, 0x00, 0x00, + 0x26, 0xdb, 0x26, 0xdb, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_30[180] = { + 0x55, 0x11, 0x55, 0x11, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, + 0x80, 0x45, 0x80, 0x45, 0x00, 0x00, + 0x20, 0x1a, 0x20, 0x1a, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x22, 0x84, 0x22, 0x84, 0x00, 0x00, + 0x48, 0x09, 0x48, 0x09, 0x00, 0x00, + 0x07, 0x01, 0x07, 0x01, 0x00, 0x00, + 0x94, 0x20, 0x94, 0x20, 0x00, 0x00, + 0x82, 0x06, 0x82, 0x06, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x89, 0x80, 0x89, 0x80, 0x00, 0x00, + 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x00, + 0x18, 0x22, 0x18, 0x22, 0x00, 0x00, + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x22, 0x0a, 0x22, 0x0a, 0x00, 0x00, + 0x84, 0xd0, 0x84, 0xd0, 0x00, 0x00, + 0x0c, 0x8a, 0x0c, 0x8a, 0x00, 0x00, + 0x18, 0x06, 0x18, 0x06, 0x00, 0x00, + 0x30, 0x03, 0x30, 0x03, 0x00, 0x00, + 0x61, 0x08, 0x61, 0x08, 0x00, 0x00, + 0x40, 0x11, 0x40, 0x11, 0x00, 0x00, + 0x10, 0x2c, 0x10, 0x2c, 0x00, 0x00, + 0x09, 0x60, 0x09, 0x60, 0x00, 0x00, + 0x00, 0x94, 0x00, 0x94, 0x00, 0x00, + 0x52, 0x40, 0x52, 0x40, 0x00, 0x00, + 0xa4, 0x24, 0xa4, 0x24, 0x00, 0x00, + 0x82, 0x88, 0x82, 0x88, 0x00, 0x00, + 0x1e, 0x27, 0xe2, 0xd8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_31[186] = { + 0x55, 0x11, 0x55, 0x11, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, + 0x80, 0x45, 0x80, 0x45, 0x00, 0x00, + 0x20, 0x1a, 0x20, 0x1a, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x22, 0x84, 0x22, 0x84, 0x00, 0x00, + 0x48, 0x09, 0x48, 0x09, 0x00, 0x00, + 0x07, 0x01, 0x07, 0x01, 0x00, 0x00, + 0x94, 0x20, 0x94, 0x20, 0x00, 0x00, + 0x82, 0x06, 0x82, 0x06, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x89, 0x80, 0x89, 0x80, 0x00, 0x00, + 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x00, + 0x18, 0x22, 0x18, 0x22, 0x00, 0x00, + 0xa4, 0x10, 0xa4, 0x10, 0x00, 0x00, + 0x01, 0x2a, 0x01, 0x2a, 0x00, 0x00, + 0x06, 0x42, 0x06, 0x42, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x81, 0x90, 0x81, 0x90, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, + 0x50, 0x05, 0x50, 0x05, 0x00, 0x00, + 0x20, 0x51, 0x20, 0x51, 0x00, 0x00, + 0x43, 0x08, 0x43, 0x08, 0x00, 0x00, + 0x68, 0x80, 0x68, 0x80, 0x00, 0x00, + 0x80, 0x0b, 0x80, 0x0b, 0x00, 0x00, + 0x10, 0x4c, 0x10, 0x4c, 0x00, 0x00, + 0x12, 0x30, 0x12, 0x30, 0x00, 0x00, + 0x40, 0x85, 0x40, 0x85, 0x00, 0x00, + 0x0e, 0x04, 0x0e, 0x04, 0x00, 0x00, + 0x18, 0x12, 0x18, 0x12, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_32[192] = { + 0xa4, 0x10, 0xa4, 0x10, 0x00, 0x00, + 0x01, 0x2a, 0x01, 0x2a, 0x00, 0x00, + 0x06, 0x42, 0x06, 0x42, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x81, 0x90, 0x81, 0x90, 0x00, 0x00, + 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x00, + 0x50, 0x05, 0x50, 0x05, 0x00, 0x00, + 0x20, 0x51, 0x20, 0x51, 0x00, 0x00, + 0x43, 0x08, 0x43, 0x08, 0x00, 0x00, + 0x68, 0x80, 0x68, 0x80, 0x00, 0x00, + 0x80, 0x0b, 0x80, 0x0b, 0x00, 0x00, + 0x10, 0x4c, 0x10, 0x4c, 0x00, 0x00, + 0x12, 0x30, 0x12, 0x30, 0x00, 0x00, + 0x40, 0x85, 0x40, 0x85, 0x00, 0x00, + 0x0e, 0x04, 0x0e, 0x04, 0x00, 0x00, + 0x18, 0x12, 0x18, 0x12, 0x00, 0x00, + 0x55, 0x11, 0x55, 0x11, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, + 0x80, 0x45, 0x80, 0x45, 0x00, 0x00, + 0x20, 0x1a, 0x20, 0x1a, 0x00, 0x00, + 0x08, 0x68, 0x08, 0x68, 0x00, 0x00, + 0x22, 0x84, 0x22, 0x84, 0x00, 0x00, + 0x48, 0x09, 0x48, 0x09, 0x00, 0x00, + 0x07, 0x01, 0x07, 0x01, 0x00, 0x00, + 0x94, 0x20, 0x94, 0x20, 0x00, 0x00, + 0x82, 0x06, 0x82, 0x06, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x89, 0x80, 0x89, 0x80, 0x00, 0x00, + 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x00, + 0x18, 0x22, 0x18, 0x22, 0x00, 0x00, + 0x60, 0xc4, 0x02, 0x02, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_4[24] = { + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, + 0x35, 0x35, 0x35, 0x35, 0x00, 0x00, + 0xca, 0xca, 0xca, 0xca, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_5[30] = { + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x2a, 0x2a, 0x2a, 0x2a, 0x00, 0x00, + 0x24, 0x25, 0x24, 0x25, 0x00, 0x00, + 0x84, 0xc8, 0x84, 0xc8, 0x00, 0x00, + 0x10, 0xb6, 0x10, 0xb6, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_6[36] = { + 0x51, 0x51, 0x51, 0x51, 0x00, 0x00, + 0x0a, 0x2a, 0x0a, 0x2a, 0x00, 0x00, + 0xa2, 0x15, 0xa2, 0x15, 0x00, 0x00, + 0x84, 0x4a, 0x84, 0x4a, 0x00, 0x00, + 0x30, 0x92, 0x30, 0x92, 0x00, 0x00, + 0x04, 0xac, 0x04, 0xac, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_7[42] = { + 0x45, 0x51, 0x45, 0x51, 0x00, 0x00, + 0x22, 0x2a, 0x22, 0x2a, 0x00, 0x00, + 0x91, 0x11, 0x91, 0x11, 0x00, 0x00, + 0x2e, 0x08, 0x2e, 0x08, 0x00, 0x00, + 0x48, 0x34, 0x48, 0x34, 0x00, 0x00, + 0x90, 0x29, 0x90, 0x29, 0x00, 0x00, + 0x09, 0x86, 0x09, 0x86, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_8[48] = { + 0x20, 0x54, 0x20, 0x54, 0x00, 0x00, + 0x18, 0x88, 0x18, 0x88, 0x00, 0x00, + 0x84, 0x07, 0x84, 0x07, 0x00, 0x00, + 0x60, 0x48, 0x60, 0x48, 0x00, 0x00, + 0x12, 0x82, 0x12, 0x82, 0x00, 0x00, + 0x81, 0x41, 0x81, 0x41, 0x00, 0x00, + 0x40, 0x62, 0x40, 0x62, 0x00, 0x00, + 0x16, 0x30, 0x16, 0x30, 0x00, 0x00 +}; + +const uint8_t kMaskRandom32_9[54] = { + 0x55, 0x51, 0x55, 0x51, 0x00, 0x00, + 0x22, 0x2a, 0x22, 0x2a, 0x00, 0x00, + 0x05, 0x85, 0x05, 0x85, 0x00, 0x00, + 0x09, 0x4a, 0x09, 0x4a, 0x00, 0x00, + 0x84, 0x32, 0x84, 0x32, 0x00, 0x00, + 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x00, + 0x20, 0xa6, 0x20, 0xa6, 0x00, 0x00, + 0x1a, 0x09, 0x1a, 0x09, 0x00, 0x00, + 0x44, 0x64, 0x44, 0x64, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_10[60] = { + 0x45, 0x51, 0x55, 0x8c, 0x80, 0x00, + 0x10, 0xa2, 0xaa, 0x27, 0x00, 0x00, + 0x01, 0x25, 0xa5, 0x32, 0x80, 0x00, + 0x0b, 0x42, 0x62, 0x61, 0x80, 0x00, + 0xd8, 0x20, 0x3c, 0x5c, 0x00, 0x00, + 0x82, 0x8c, 0x8e, 0xcc, 0x00, 0x00, + 0x24, 0x4a, 0x6a, 0x2b, 0x00, 0x00, + 0x38, 0x18, 0x36, 0x32, 0x80, 0x00, + 0x2a, 0x25, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x92, 0xc8, 0x02, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_11[66] = { + 0x55, 0x55, 0x55, 0x8c, 0x80, 0x00, + 0x2a, 0x22, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x11, 0xa5, 0x32, 0x80, 0x00, + 0x83, 0x42, 0x62, 0x61, 0x80, 0x00, + 0x06, 0x98, 0x3c, 0x5c, 0x00, 0x00, + 0x40, 0xe1, 0x51, 0x84, 0x80, 0x00, + 0x2c, 0x44, 0xa2, 0x27, 0x00, 0x00, + 0xd8, 0x28, 0x95, 0x51, 0x80, 0x00, + 0x92, 0x81, 0x4a, 0x1a, 0x00, 0x00, + 0x84, 0x32, 0x30, 0x68, 0x00, 0x00, + 0x68, 0x0c, 0x2c, 0x89, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_12[72] = { + 0x84, 0x31, 0x51, 0x84, 0x80, 0x00, + 0x18, 0xa2, 0xa2, 0x27, 0x00, 0x00, + 0x4e, 0x01, 0x95, 0x51, 0x80, 0x00, + 0x44, 0xc8, 0x4a, 0x1a, 0x00, 0x00, + 0x0e, 0x90, 0x30, 0x68, 0x00, 0x00, + 0x20, 0xcc, 0x2c, 0x89, 0x00, 0x00, + 0x93, 0x40, 0x55, 0x8c, 0x80, 0x00, + 0x2d, 0x10, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x44, 0xa5, 0x32, 0x80, 0x00, + 0xc0, 0x23, 0x62, 0x61, 0x80, 0x00, + 0x11, 0x25, 0x3c, 0x5c, 0x00, 0x00, + 0xe8, 0x80, 0x51, 0x35, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_13[78] = { + 0x45, 0x15, 0x51, 0x84, 0x80, 0x00, + 0x22, 0x22, 0xa2, 0x27, 0x00, 0x00, + 0x96, 0x0c, 0x95, 0x51, 0x80, 0x00, + 0x0c, 0x50, 0x4a, 0x1a, 0x00, 0x00, + 0x62, 0x04, 0x30, 0x68, 0x00, 0x00, + 0x49, 0x06, 0x2c, 0x89, 0x00, 0x00, + 0x11, 0x82, 0x15, 0x8c, 0x00, 0x00, + 0x12, 0x38, 0x8a, 0x47, 0x00, 0x00, + 0x40, 0x71, 0x25, 0x81, 0x80, 0x00, + 0xa8, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x08, 0xa1, 0x58, 0x58, 0x00, 0x00, + 0xa0, 0xc0, 0x0e, 0x28, 0x80, 0x00, + 0xc5, 0x10, 0x83, 0x34, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_14[84] = { + 0x45, 0x51, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x0a, 0x8a, 0x47, 0x00, 0x00, + 0x84, 0xd0, 0x25, 0x81, 0x80, 0x00, + 0x0c, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x18, 0x06, 0x58, 0x58, 0x00, 0x00, + 0x30, 0x03, 0x0e, 0x28, 0x80, 0x00, + 0x61, 0x08, 0x83, 0x34, 0x00, 0x00, + 0x40, 0x11, 0x51, 0x84, 0x80, 0x00, + 0x10, 0x2c, 0xa2, 0x27, 0x00, 0x00, + 0x09, 0x60, 0x95, 0x51, 0x80, 0x00, + 0x00, 0x94, 0x4a, 0x1a, 0x00, 0x00, + 0x52, 0x40, 0x30, 0x68, 0x00, 0x00, + 0xa4, 0x24, 0x2c, 0x89, 0x00, 0x00, + 0x82, 0x88, 0xb0, 0xde, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_15[90] = { + 0x55, 0x11, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x22, 0x8a, 0x47, 0x00, 0x00, + 0x11, 0x11, 0x25, 0x81, 0x80, 0x00, + 0x80, 0x45, 0x62, 0x12, 0x80, 0x00, + 0x20, 0x1a, 0x58, 0x58, 0x00, 0x00, + 0x08, 0x68, 0x0e, 0x28, 0x80, 0x00, + 0x22, 0x84, 0x83, 0x34, 0x00, 0x00, + 0x48, 0x09, 0x25, 0x2c, 0x00, 0x00, + 0x07, 0x01, 0x8a, 0x91, 0x00, 0x00, + 0x94, 0x20, 0x91, 0xc0, 0x80, 0x00, + 0x82, 0x06, 0x68, 0x06, 0x80, 0x00, + 0x60, 0x48, 0x32, 0xc8, 0x00, 0x00, + 0x89, 0x80, 0x43, 0x45, 0x00, 0x00, + 0x00, 0x8e, 0xc4, 0x30, 0x80, 0x00, + 0x18, 0x22, 0x1c, 0xa2, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_16[96] = { + 0xa4, 0x10, 0x25, 0x2c, 0x00, 0x00, + 0x01, 0x2a, 0x8a, 0x91, 0x00, 0x00, + 0x06, 0x42, 0x91, 0xc0, 0x80, 0x00, + 0x08, 0x68, 0x68, 0x06, 0x80, 0x00, + 0x81, 0x90, 0x32, 0xc8, 0x00, 0x00, + 0x00, 0xf0, 0x43, 0x45, 0x00, 0x00, + 0x50, 0x05, 0xc4, 0x30, 0x80, 0x00, + 0x20, 0x51, 0x1c, 0xa2, 0x00, 0x00, + 0x43, 0x08, 0x15, 0x8c, 0x00, 0x00, + 0x68, 0x80, 0x8a, 0x47, 0x00, 0x00, + 0x80, 0x0b, 0x25, 0x81, 0x80, 0x00, + 0x10, 0x4c, 0x62, 0x12, 0x80, 0x00, + 0x12, 0x30, 0x58, 0x58, 0x00, 0x00, + 0x40, 0x85, 0x0e, 0x28, 0x80, 0x00, + 0x0e, 0x04, 0x83, 0x34, 0x00, 0x00, + 0x18, 0x12, 0x0a, 0x1c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_17[102] = { + 0x20, 0x54, 0x64, 0x16, 0x00, 0x00, + 0x18, 0x88, 0xa2, 0xc2, 0x00, 0x00, + 0x84, 0x07, 0x51, 0x60, 0x80, 0x00, + 0x60, 0x48, 0x4a, 0x85, 0x00, 0x00, + 0x12, 0x82, 0x38, 0x4c, 0x00, 0x00, + 0x81, 0x41, 0x89, 0x29, 0x00, 0x00, + 0x40, 0x62, 0x07, 0x11, 0x80, 0x00, + 0x16, 0x30, 0x94, 0xb0, 0x00, 0x00, + 0x55, 0x51, 0x8e, 0xcc, 0x00, 0x00, + 0x22, 0x2a, 0x6a, 0x2b, 0x00, 0x00, + 0x05, 0x85, 0x36, 0x32, 0x80, 0x00, + 0x09, 0x4a, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x32, 0x55, 0x8c, 0x80, 0x00, + 0xc0, 0x0d, 0xaa, 0x27, 0x00, 0x00, + 0x20, 0xa6, 0xa5, 0x32, 0x80, 0x00, + 0x1a, 0x09, 0x62, 0x61, 0x80, 0x00, + 0x44, 0x64, 0x3c, 0x5c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_18[108] = { + 0x55, 0x51, 0x8e, 0xcc, 0x00, 0x00, + 0x22, 0x2a, 0x6a, 0x2b, 0x00, 0x00, + 0x05, 0x85, 0x36, 0x32, 0x80, 0x00, + 0x09, 0x4a, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x32, 0x55, 0x8c, 0x80, 0x00, + 0xc0, 0x0d, 0xaa, 0x27, 0x00, 0x00, + 0x20, 0xa6, 0xa5, 0x32, 0x80, 0x00, + 0x1a, 0x09, 0x62, 0x61, 0x80, 0x00, + 0x44, 0x64, 0x3c, 0x5c, 0x00, 0x00, + 0x20, 0x54, 0x64, 0x16, 0x00, 0x00, + 0x18, 0x88, 0xa2, 0xc2, 0x00, 0x00, + 0x84, 0x07, 0x51, 0x60, 0x80, 0x00, + 0x60, 0x48, 0x4a, 0x85, 0x00, 0x00, + 0x12, 0x82, 0x38, 0x4c, 0x00, 0x00, + 0x81, 0x41, 0x89, 0x29, 0x00, 0x00, + 0x40, 0x62, 0x07, 0x11, 0x80, 0x00, + 0x16, 0x30, 0x94, 0xb0, 0x00, 0x00, + 0x89, 0x53, 0x03, 0xad, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_19[114] = { + 0x55, 0x51, 0x8e, 0xcc, 0x00, 0x00, + 0x22, 0x2a, 0x6a, 0x2b, 0x00, 0x00, + 0x05, 0x85, 0x36, 0x32, 0x80, 0x00, + 0x09, 0x4a, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x32, 0x55, 0x8c, 0x80, 0x00, + 0xc0, 0x0d, 0xaa, 0x27, 0x00, 0x00, + 0x20, 0xa6, 0xa5, 0x32, 0x80, 0x00, + 0x1a, 0x09, 0x62, 0x61, 0x80, 0x00, + 0x44, 0x64, 0x3c, 0x5c, 0x00, 0x00, + 0x45, 0x51, 0x55, 0x8c, 0x80, 0x00, + 0x10, 0xa2, 0xaa, 0x27, 0x00, 0x00, + 0x01, 0x25, 0xa5, 0x32, 0x80, 0x00, + 0x0b, 0x42, 0x62, 0x61, 0x80, 0x00, + 0xd8, 0x20, 0x3c, 0x5c, 0x00, 0x00, + 0x82, 0x8c, 0x8e, 0xcc, 0x00, 0x00, + 0x24, 0x4a, 0x6a, 0x2b, 0x00, 0x00, + 0x38, 0x18, 0x36, 0x32, 0x80, 0x00, + 0x2a, 0x25, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x92, 0xc8, 0x02, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_2[12] = { + 0xae, 0xae, 0xce, 0xce, 0x00, 0x00, + 0x79, 0x79, 0xb9, 0x39, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_20[120] = { + 0x45, 0x51, 0x55, 0x8c, 0x80, 0x00, + 0x10, 0xa2, 0xaa, 0x27, 0x00, 0x00, + 0x01, 0x25, 0xa5, 0x32, 0x80, 0x00, + 0x0b, 0x42, 0x62, 0x61, 0x80, 0x00, + 0xd8, 0x20, 0x3c, 0x5c, 0x00, 0x00, + 0x82, 0x8c, 0x8e, 0xcc, 0x00, 0x00, + 0x24, 0x4a, 0x6a, 0x2b, 0x00, 0x00, + 0x38, 0x18, 0x36, 0x32, 0x80, 0x00, + 0x2a, 0x25, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x92, 0xc8, 0x02, 0x80, 0x00, + 0x55, 0x51, 0x8e, 0xcc, 0x00, 0x00, + 0x22, 0x2a, 0x6a, 0x2b, 0x00, 0x00, + 0x05, 0x85, 0x36, 0x32, 0x80, 0x00, + 0x09, 0x4a, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x32, 0x55, 0x8c, 0x80, 0x00, + 0xc0, 0x0d, 0xaa, 0x27, 0x00, 0x00, + 0x20, 0xa6, 0xa5, 0x32, 0x80, 0x00, + 0x1a, 0x09, 0x62, 0x61, 0x80, 0x00, + 0x44, 0x64, 0x3c, 0x5c, 0x00, 0x00, + 0x73, 0x5f, 0x5b, 0x0e, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_21[126] = { + 0x45, 0x51, 0x55, 0x8c, 0x80, 0x00, + 0x10, 0xa2, 0xaa, 0x27, 0x00, 0x00, + 0x01, 0x25, 0xa5, 0x32, 0x80, 0x00, + 0x0b, 0x42, 0x62, 0x61, 0x80, 0x00, + 0xd8, 0x20, 0x3c, 0x5c, 0x00, 0x00, + 0x82, 0x8c, 0x8e, 0xcc, 0x00, 0x00, + 0x24, 0x4a, 0x6a, 0x2b, 0x00, 0x00, + 0x38, 0x18, 0x36, 0x32, 0x80, 0x00, + 0x2a, 0x25, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x92, 0xc8, 0x02, 0x80, 0x00, + 0x55, 0x55, 0x55, 0x8c, 0x80, 0x00, + 0x2a, 0x22, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x11, 0xa5, 0x32, 0x80, 0x00, + 0x83, 0x42, 0x62, 0x61, 0x80, 0x00, + 0x06, 0x98, 0x3c, 0x5c, 0x00, 0x00, + 0x40, 0xe1, 0x51, 0x84, 0x80, 0x00, + 0x2c, 0x44, 0xa2, 0x27, 0x00, 0x00, + 0xd8, 0x28, 0x95, 0x51, 0x80, 0x00, + 0x92, 0x81, 0x4a, 0x1a, 0x00, 0x00, + 0x84, 0x32, 0x30, 0x68, 0x00, 0x00, + 0x68, 0x0c, 0x2c, 0x89, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_22[132] = { + 0x55, 0x55, 0x55, 0x8c, 0x80, 0x00, + 0x2a, 0x22, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x11, 0xa5, 0x32, 0x80, 0x00, + 0x83, 0x42, 0x62, 0x61, 0x80, 0x00, + 0x06, 0x98, 0x3c, 0x5c, 0x00, 0x00, + 0x40, 0xe1, 0x51, 0x84, 0x80, 0x00, + 0x2c, 0x44, 0xa2, 0x27, 0x00, 0x00, + 0xd8, 0x28, 0x95, 0x51, 0x80, 0x00, + 0x92, 0x81, 0x4a, 0x1a, 0x00, 0x00, + 0x84, 0x32, 0x30, 0x68, 0x00, 0x00, + 0x68, 0x0c, 0x2c, 0x89, 0x00, 0x00, + 0x45, 0x51, 0x55, 0x8c, 0x80, 0x00, + 0x10, 0xa2, 0xaa, 0x27, 0x00, 0x00, + 0x01, 0x25, 0xa5, 0x32, 0x80, 0x00, + 0x0b, 0x42, 0x62, 0x61, 0x80, 0x00, + 0xd8, 0x20, 0x3c, 0x5c, 0x00, 0x00, + 0x82, 0x8c, 0x8e, 0xcc, 0x00, 0x00, + 0x24, 0x4a, 0x6a, 0x2b, 0x00, 0x00, + 0x38, 0x18, 0x36, 0x32, 0x80, 0x00, + 0x2a, 0x25, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x92, 0xc8, 0x02, 0x80, 0x00, + 0xcc, 0xe3, 0x42, 0x6b, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_23[138] = { + 0x55, 0x55, 0x55, 0x8c, 0x80, 0x00, + 0x2a, 0x22, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x11, 0xa5, 0x32, 0x80, 0x00, + 0x83, 0x42, 0x62, 0x61, 0x80, 0x00, + 0x06, 0x98, 0x3c, 0x5c, 0x00, 0x00, + 0x40, 0xe1, 0x51, 0x84, 0x80, 0x00, + 0x2c, 0x44, 0xa2, 0x27, 0x00, 0x00, + 0xd8, 0x28, 0x95, 0x51, 0x80, 0x00, + 0x92, 0x81, 0x4a, 0x1a, 0x00, 0x00, + 0x84, 0x32, 0x30, 0x68, 0x00, 0x00, + 0x68, 0x0c, 0x2c, 0x89, 0x00, 0x00, + 0x84, 0x31, 0x51, 0x84, 0x80, 0x00, + 0x18, 0xa2, 0xa2, 0x27, 0x00, 0x00, + 0x4e, 0x01, 0x95, 0x51, 0x80, 0x00, + 0x44, 0xc8, 0x4a, 0x1a, 0x00, 0x00, + 0x0e, 0x90, 0x30, 0x68, 0x00, 0x00, + 0x20, 0xcc, 0x2c, 0x89, 0x00, 0x00, + 0x93, 0x40, 0x55, 0x8c, 0x80, 0x00, + 0x2d, 0x10, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x44, 0xa5, 0x32, 0x80, 0x00, + 0xc0, 0x23, 0x62, 0x61, 0x80, 0x00, + 0x11, 0x25, 0x3c, 0x5c, 0x00, 0x00, + 0xe8, 0x80, 0x51, 0x35, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_24[144] = { + 0x84, 0x31, 0x51, 0x84, 0x80, 0x00, + 0x18, 0xa2, 0xa2, 0x27, 0x00, 0x00, + 0x4e, 0x01, 0x95, 0x51, 0x80, 0x00, + 0x44, 0xc8, 0x4a, 0x1a, 0x00, 0x00, + 0x0e, 0x90, 0x30, 0x68, 0x00, 0x00, + 0x20, 0xcc, 0x2c, 0x89, 0x00, 0x00, + 0x93, 0x40, 0x55, 0x8c, 0x80, 0x00, + 0x2d, 0x10, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x44, 0xa5, 0x32, 0x80, 0x00, + 0xc0, 0x23, 0x62, 0x61, 0x80, 0x00, + 0x11, 0x25, 0x3c, 0x5c, 0x00, 0x00, + 0xe8, 0x80, 0x51, 0x35, 0x00, 0x00, + 0x55, 0x55, 0x55, 0x8c, 0x80, 0x00, + 0x2a, 0x22, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x11, 0xa5, 0x32, 0x80, 0x00, + 0x83, 0x42, 0x62, 0x61, 0x80, 0x00, + 0x06, 0x98, 0x3c, 0x5c, 0x00, 0x00, + 0x40, 0xe1, 0x51, 0x84, 0x80, 0x00, + 0x2c, 0x44, 0xa2, 0x27, 0x00, 0x00, + 0xd8, 0x28, 0x95, 0x51, 0x80, 0x00, + 0x92, 0x81, 0x4a, 0x1a, 0x00, 0x00, + 0x84, 0x32, 0x30, 0x68, 0x00, 0x00, + 0x68, 0x0c, 0x2c, 0x89, 0x00, 0x00, + 0xdc, 0x4e, 0xfc, 0x70, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_25[150] = { + 0x84, 0x31, 0x51, 0x84, 0x80, 0x00, + 0x18, 0xa2, 0xa2, 0x27, 0x00, 0x00, + 0x4e, 0x01, 0x95, 0x51, 0x80, 0x00, + 0x44, 0xc8, 0x4a, 0x1a, 0x00, 0x00, + 0x0e, 0x90, 0x30, 0x68, 0x00, 0x00, + 0x20, 0xcc, 0x2c, 0x89, 0x00, 0x00, + 0x93, 0x40, 0x55, 0x8c, 0x80, 0x00, + 0x2d, 0x10, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x44, 0xa5, 0x32, 0x80, 0x00, + 0xc0, 0x23, 0x62, 0x61, 0x80, 0x00, + 0x11, 0x25, 0x3c, 0x5c, 0x00, 0x00, + 0xe8, 0x80, 0x51, 0x35, 0x00, 0x00, + 0x45, 0x15, 0x51, 0x84, 0x80, 0x00, + 0x22, 0x22, 0xa2, 0x27, 0x00, 0x00, + 0x96, 0x0c, 0x95, 0x51, 0x80, 0x00, + 0x0c, 0x50, 0x4a, 0x1a, 0x00, 0x00, + 0x62, 0x04, 0x30, 0x68, 0x00, 0x00, + 0x49, 0x06, 0x2c, 0x89, 0x00, 0x00, + 0x11, 0x82, 0x15, 0x8c, 0x00, 0x00, + 0x12, 0x38, 0x8a, 0x47, 0x00, 0x00, + 0x40, 0x71, 0x25, 0x81, 0x80, 0x00, + 0xa8, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x08, 0xa1, 0x58, 0x58, 0x00, 0x00, + 0xa0, 0xc0, 0x0e, 0x28, 0x80, 0x00, + 0xc5, 0x10, 0x83, 0x34, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_26[156] = { + 0x45, 0x15, 0x51, 0x84, 0x80, 0x00, + 0x22, 0x22, 0xa2, 0x27, 0x00, 0x00, + 0x96, 0x0c, 0x95, 0x51, 0x80, 0x00, + 0x0c, 0x50, 0x4a, 0x1a, 0x00, 0x00, + 0x62, 0x04, 0x30, 0x68, 0x00, 0x00, + 0x49, 0x06, 0x2c, 0x89, 0x00, 0x00, + 0x11, 0x82, 0x15, 0x8c, 0x00, 0x00, + 0x12, 0x38, 0x8a, 0x47, 0x00, 0x00, + 0x40, 0x71, 0x25, 0x81, 0x80, 0x00, + 0xa8, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x08, 0xa1, 0x58, 0x58, 0x00, 0x00, + 0xa0, 0xc0, 0x0e, 0x28, 0x80, 0x00, + 0xc5, 0x10, 0x83, 0x34, 0x00, 0x00, + 0x84, 0x31, 0x51, 0x84, 0x80, 0x00, + 0x18, 0xa2, 0xa2, 0x27, 0x00, 0x00, + 0x4e, 0x01, 0x95, 0x51, 0x80, 0x00, + 0x44, 0xc8, 0x4a, 0x1a, 0x00, 0x00, + 0x0e, 0x90, 0x30, 0x68, 0x00, 0x00, + 0x20, 0xcc, 0x2c, 0x89, 0x00, 0x00, + 0x93, 0x40, 0x55, 0x8c, 0x80, 0x00, + 0x2d, 0x10, 0xaa, 0x27, 0x00, 0x00, + 0x31, 0x44, 0xa5, 0x32, 0x80, 0x00, + 0xc0, 0x23, 0x62, 0x61, 0x80, 0x00, + 0x11, 0x25, 0x3c, 0x5c, 0x00, 0x00, + 0xe8, 0x80, 0x51, 0x35, 0x00, 0x00, + 0xa4, 0xa4, 0xfc, 0x91, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_27[162] = { + 0x45, 0x15, 0x51, 0x84, 0x80, 0x00, + 0x22, 0x22, 0xa2, 0x27, 0x00, 0x00, + 0x96, 0x0c, 0x95, 0x51, 0x80, 0x00, + 0x0c, 0x50, 0x4a, 0x1a, 0x00, 0x00, + 0x62, 0x04, 0x30, 0x68, 0x00, 0x00, + 0x49, 0x06, 0x2c, 0x89, 0x00, 0x00, + 0x11, 0x82, 0x15, 0x8c, 0x00, 0x00, + 0x12, 0x38, 0x8a, 0x47, 0x00, 0x00, + 0x40, 0x71, 0x25, 0x81, 0x80, 0x00, + 0xa8, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x08, 0xa1, 0x58, 0x58, 0x00, 0x00, + 0xa0, 0xc0, 0x0e, 0x28, 0x80, 0x00, + 0xc5, 0x10, 0x83, 0x34, 0x00, 0x00, + 0x45, 0x51, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x0a, 0x8a, 0x47, 0x00, 0x00, + 0x84, 0xd0, 0x25, 0x81, 0x80, 0x00, + 0x0c, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x18, 0x06, 0x58, 0x58, 0x00, 0x00, + 0x30, 0x03, 0x0e, 0x28, 0x80, 0x00, + 0x61, 0x08, 0x83, 0x34, 0x00, 0x00, + 0x40, 0x11, 0x51, 0x84, 0x80, 0x00, + 0x10, 0x2c, 0xa2, 0x27, 0x00, 0x00, + 0x09, 0x60, 0x95, 0x51, 0x80, 0x00, + 0x00, 0x94, 0x4a, 0x1a, 0x00, 0x00, + 0x52, 0x40, 0x30, 0x68, 0x00, 0x00, + 0xa4, 0x24, 0x2c, 0x89, 0x00, 0x00, + 0x82, 0x88, 0xb0, 0xde, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_28[168] = { + 0x45, 0x51, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x0a, 0x8a, 0x47, 0x00, 0x00, + 0x84, 0xd0, 0x25, 0x81, 0x80, 0x00, + 0x0c, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x18, 0x06, 0x58, 0x58, 0x00, 0x00, + 0x30, 0x03, 0x0e, 0x28, 0x80, 0x00, + 0x61, 0x08, 0x83, 0x34, 0x00, 0x00, + 0x40, 0x11, 0x51, 0x84, 0x80, 0x00, + 0x10, 0x2c, 0xa2, 0x27, 0x00, 0x00, + 0x09, 0x60, 0x95, 0x51, 0x80, 0x00, + 0x00, 0x94, 0x4a, 0x1a, 0x00, 0x00, + 0x52, 0x40, 0x30, 0x68, 0x00, 0x00, + 0xa4, 0x24, 0x2c, 0x89, 0x00, 0x00, + 0x82, 0x88, 0xb0, 0xde, 0x80, 0x00, + 0x45, 0x15, 0x51, 0x84, 0x80, 0x00, + 0x22, 0x22, 0xa2, 0x27, 0x00, 0x00, + 0x96, 0x0c, 0x95, 0x51, 0x80, 0x00, + 0x0c, 0x50, 0x4a, 0x1a, 0x00, 0x00, + 0x62, 0x04, 0x30, 0x68, 0x00, 0x00, + 0x49, 0x06, 0x2c, 0x89, 0x00, 0x00, + 0x11, 0x82, 0x15, 0x8c, 0x00, 0x00, + 0x12, 0x38, 0x8a, 0x47, 0x00, 0x00, + 0x40, 0x71, 0x25, 0x81, 0x80, 0x00, + 0xa8, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x08, 0xa1, 0x58, 0x58, 0x00, 0x00, + 0xa0, 0xc0, 0x0e, 0x28, 0x80, 0x00, + 0xc5, 0x10, 0x83, 0x34, 0x00, 0x00, + 0x1b, 0xf4, 0xaa, 0xec, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_29[174] = { + 0x45, 0x51, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x0a, 0x8a, 0x47, 0x00, 0x00, + 0x84, 0xd0, 0x25, 0x81, 0x80, 0x00, + 0x0c, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x18, 0x06, 0x58, 0x58, 0x00, 0x00, + 0x30, 0x03, 0x0e, 0x28, 0x80, 0x00, + 0x61, 0x08, 0x83, 0x34, 0x00, 0x00, + 0x40, 0x11, 0x51, 0x84, 0x80, 0x00, + 0x10, 0x2c, 0xa2, 0x27, 0x00, 0x00, + 0x09, 0x60, 0x95, 0x51, 0x80, 0x00, + 0x00, 0x94, 0x4a, 0x1a, 0x00, 0x00, + 0x52, 0x40, 0x30, 0x68, 0x00, 0x00, + 0xa4, 0x24, 0x2c, 0x89, 0x00, 0x00, + 0x82, 0x88, 0xb0, 0xde, 0x80, 0x00, + 0x55, 0x11, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x22, 0x8a, 0x47, 0x00, 0x00, + 0x11, 0x11, 0x25, 0x81, 0x80, 0x00, + 0x80, 0x45, 0x62, 0x12, 0x80, 0x00, + 0x20, 0x1a, 0x58, 0x58, 0x00, 0x00, + 0x08, 0x68, 0x0e, 0x28, 0x80, 0x00, + 0x22, 0x84, 0x83, 0x34, 0x00, 0x00, + 0x48, 0x09, 0x25, 0x2c, 0x00, 0x00, + 0x07, 0x01, 0x8a, 0x91, 0x00, 0x00, + 0x94, 0x20, 0x91, 0xc0, 0x80, 0x00, + 0x82, 0x06, 0x68, 0x06, 0x80, 0x00, + 0x60, 0x48, 0x32, 0xc8, 0x00, 0x00, + 0x89, 0x80, 0x43, 0x45, 0x00, 0x00, + 0x00, 0x8e, 0xc4, 0x30, 0x80, 0x00, + 0x18, 0x22, 0x1c, 0xa2, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_3[18] = { + 0xad, 0x2d, 0xcd, 0xcc, 0x00, 0x00, + 0x76, 0x36, 0x97, 0x27, 0x00, 0x00, + 0x26, 0xdb, 0xb8, 0xd1, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_30[180] = { + 0x55, 0x11, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x22, 0x8a, 0x47, 0x00, 0x00, + 0x11, 0x11, 0x25, 0x81, 0x80, 0x00, + 0x80, 0x45, 0x62, 0x12, 0x80, 0x00, + 0x20, 0x1a, 0x58, 0x58, 0x00, 0x00, + 0x08, 0x68, 0x0e, 0x28, 0x80, 0x00, + 0x22, 0x84, 0x83, 0x34, 0x00, 0x00, + 0x48, 0x09, 0x25, 0x2c, 0x00, 0x00, + 0x07, 0x01, 0x8a, 0x91, 0x00, 0x00, + 0x94, 0x20, 0x91, 0xc0, 0x80, 0x00, + 0x82, 0x06, 0x68, 0x06, 0x80, 0x00, + 0x60, 0x48, 0x32, 0xc8, 0x00, 0x00, + 0x89, 0x80, 0x43, 0x45, 0x00, 0x00, + 0x00, 0x8e, 0xc4, 0x30, 0x80, 0x00, + 0x18, 0x22, 0x1c, 0xa2, 0x00, 0x00, + 0x45, 0x51, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x0a, 0x8a, 0x47, 0x00, 0x00, + 0x84, 0xd0, 0x25, 0x81, 0x80, 0x00, + 0x0c, 0x8a, 0x62, 0x12, 0x80, 0x00, + 0x18, 0x06, 0x58, 0x58, 0x00, 0x00, + 0x30, 0x03, 0x0e, 0x28, 0x80, 0x00, + 0x61, 0x08, 0x83, 0x34, 0x00, 0x00, + 0x40, 0x11, 0x51, 0x84, 0x80, 0x00, + 0x10, 0x2c, 0xa2, 0x27, 0x00, 0x00, + 0x09, 0x60, 0x95, 0x51, 0x80, 0x00, + 0x00, 0x94, 0x4a, 0x1a, 0x00, 0x00, + 0x52, 0x40, 0x30, 0x68, 0x00, 0x00, + 0xa4, 0x24, 0x2c, 0x89, 0x00, 0x00, + 0x82, 0x88, 0xb0, 0xde, 0x80, 0x00, + 0x6d, 0xd2, 0x8c, 0x00, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_31[186] = { + 0x55, 0x11, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x22, 0x8a, 0x47, 0x00, 0x00, + 0x11, 0x11, 0x25, 0x81, 0x80, 0x00, + 0x80, 0x45, 0x62, 0x12, 0x80, 0x00, + 0x20, 0x1a, 0x58, 0x58, 0x00, 0x00, + 0x08, 0x68, 0x0e, 0x28, 0x80, 0x00, + 0x22, 0x84, 0x83, 0x34, 0x00, 0x00, + 0x48, 0x09, 0x25, 0x2c, 0x00, 0x00, + 0x07, 0x01, 0x8a, 0x91, 0x00, 0x00, + 0x94, 0x20, 0x91, 0xc0, 0x80, 0x00, + 0x82, 0x06, 0x68, 0x06, 0x80, 0x00, + 0x60, 0x48, 0x32, 0xc8, 0x00, 0x00, + 0x89, 0x80, 0x43, 0x45, 0x00, 0x00, + 0x00, 0x8e, 0xc4, 0x30, 0x80, 0x00, + 0x18, 0x22, 0x1c, 0xa2, 0x00, 0x00, + 0xa4, 0x10, 0x25, 0x2c, 0x00, 0x00, + 0x01, 0x2a, 0x8a, 0x91, 0x00, 0x00, + 0x06, 0x42, 0x91, 0xc0, 0x80, 0x00, + 0x08, 0x68, 0x68, 0x06, 0x80, 0x00, + 0x81, 0x90, 0x32, 0xc8, 0x00, 0x00, + 0x00, 0xf0, 0x43, 0x45, 0x00, 0x00, + 0x50, 0x05, 0xc4, 0x30, 0x80, 0x00, + 0x20, 0x51, 0x1c, 0xa2, 0x00, 0x00, + 0x43, 0x08, 0x15, 0x8c, 0x00, 0x00, + 0x68, 0x80, 0x8a, 0x47, 0x00, 0x00, + 0x80, 0x0b, 0x25, 0x81, 0x80, 0x00, + 0x10, 0x4c, 0x62, 0x12, 0x80, 0x00, + 0x12, 0x30, 0x58, 0x58, 0x00, 0x00, + 0x40, 0x85, 0x0e, 0x28, 0x80, 0x00, + 0x0e, 0x04, 0x83, 0x34, 0x00, 0x00, + 0x18, 0x12, 0x0a, 0x1c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_32[192] = { + 0xa4, 0x10, 0x25, 0x2c, 0x00, 0x00, + 0x01, 0x2a, 0x8a, 0x91, 0x00, 0x00, + 0x06, 0x42, 0x91, 0xc0, 0x80, 0x00, + 0x08, 0x68, 0x68, 0x06, 0x80, 0x00, + 0x81, 0x90, 0x32, 0xc8, 0x00, 0x00, + 0x00, 0xf0, 0x43, 0x45, 0x00, 0x00, + 0x50, 0x05, 0xc4, 0x30, 0x80, 0x00, + 0x20, 0x51, 0x1c, 0xa2, 0x00, 0x00, + 0x43, 0x08, 0x15, 0x8c, 0x00, 0x00, + 0x68, 0x80, 0x8a, 0x47, 0x00, 0x00, + 0x80, 0x0b, 0x25, 0x81, 0x80, 0x00, + 0x10, 0x4c, 0x62, 0x12, 0x80, 0x00, + 0x12, 0x30, 0x58, 0x58, 0x00, 0x00, + 0x40, 0x85, 0x0e, 0x28, 0x80, 0x00, + 0x0e, 0x04, 0x83, 0x34, 0x00, 0x00, + 0x18, 0x12, 0x0a, 0x1c, 0x00, 0x00, + 0x55, 0x11, 0x15, 0x8c, 0x00, 0x00, + 0x22, 0x22, 0x8a, 0x47, 0x00, 0x00, + 0x11, 0x11, 0x25, 0x81, 0x80, 0x00, + 0x80, 0x45, 0x62, 0x12, 0x80, 0x00, + 0x20, 0x1a, 0x58, 0x58, 0x00, 0x00, + 0x08, 0x68, 0x0e, 0x28, 0x80, 0x00, + 0x22, 0x84, 0x83, 0x34, 0x00, 0x00, + 0x48, 0x09, 0x25, 0x2c, 0x00, 0x00, + 0x07, 0x01, 0x8a, 0x91, 0x00, 0x00, + 0x94, 0x20, 0x91, 0xc0, 0x80, 0x00, + 0x82, 0x06, 0x68, 0x06, 0x80, 0x00, + 0x60, 0x48, 0x32, 0xc8, 0x00, 0x00, + 0x89, 0x80, 0x43, 0x45, 0x00, 0x00, + 0x00, 0x8e, 0xc4, 0x30, 0x80, 0x00, + 0x18, 0x22, 0x1c, 0xa2, 0x00, 0x00, + 0x73, 0x8e, 0x12, 0xca, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_33[198] = { + 0xa4, 0x10, 0x25, 0x2c, 0x00, 0x00, + 0x01, 0x2a, 0x8a, 0x91, 0x00, 0x00, + 0x06, 0x42, 0x91, 0xc0, 0x80, 0x00, + 0x08, 0x68, 0x68, 0x06, 0x80, 0x00, + 0x81, 0x90, 0x32, 0xc8, 0x00, 0x00, + 0x00, 0xf0, 0x43, 0x45, 0x00, 0x00, + 0x50, 0x05, 0xc4, 0x30, 0x80, 0x00, + 0x20, 0x51, 0x1c, 0xa2, 0x00, 0x00, + 0x43, 0x08, 0x15, 0x8c, 0x00, 0x00, + 0x68, 0x80, 0x8a, 0x47, 0x00, 0x00, + 0x80, 0x0b, 0x25, 0x81, 0x80, 0x00, + 0x10, 0x4c, 0x62, 0x12, 0x80, 0x00, + 0x12, 0x30, 0x58, 0x58, 0x00, 0x00, + 0x40, 0x85, 0x0e, 0x28, 0x80, 0x00, + 0x0e, 0x04, 0x83, 0x34, 0x00, 0x00, + 0x18, 0x12, 0x0a, 0x1c, 0x00, 0x00, + 0xa4, 0x10, 0x25, 0x2c, 0x00, 0x00, + 0x01, 0x2a, 0x8a, 0x91, 0x00, 0x00, + 0x06, 0x42, 0x91, 0xc0, 0x80, 0x00, + 0x08, 0x68, 0x68, 0x06, 0x80, 0x00, + 0x81, 0x90, 0x32, 0xc8, 0x00, 0x00, + 0x00, 0xf0, 0x43, 0x45, 0x00, 0x00, + 0x50, 0x05, 0xc4, 0x30, 0x80, 0x00, + 0x20, 0x51, 0x1c, 0xa2, 0x00, 0x00, + 0x43, 0x08, 0x25, 0x4c, 0x00, 0x00, + 0x68, 0x80, 0x8a, 0x66, 0x00, 0x00, + 0x80, 0x0b, 0x91, 0x91, 0x00, 0x00, + 0x10, 0x4c, 0x68, 0x42, 0x80, 0x00, + 0x12, 0x30, 0x32, 0xa4, 0x00, 0x00, + 0x40, 0x85, 0x43, 0x13, 0x00, 0x00, + 0x0e, 0x04, 0xc4, 0x30, 0x80, 0x00, + 0x18, 0x12, 0x1c, 0x88, 0x80, 0x00, + 0xdb, 0x10, 0x3c, 0x09, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_4[24] = { + 0x55, 0x55, 0xca, 0xec, 0x00, 0x00, + 0xaa, 0xaa, 0xa9, 0x67, 0x00, 0x00, + 0x35, 0x35, 0x3a, 0xb1, 0x80, 0x00, + 0xca, 0xca, 0x55, 0x5a, 0x80, 0x00 +}; + +const uint8_t kMaskRandom33_5[30] = { + 0x55, 0x55, 0x55, 0x44, 0x80, 0x00, + 0x2a, 0x2a, 0x2a, 0x66, 0x00, 0x00, + 0x24, 0x25, 0x25, 0xa1, 0x80, 0x00, + 0x84, 0xc8, 0xe2, 0x12, 0x80, 0x00, + 0x10, 0xb6, 0x99, 0x98, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_6[36] = { + 0x51, 0x51, 0xd1, 0x4c, 0x00, 0x00, + 0x0a, 0x2a, 0xa2, 0xc5, 0x00, 0x00, + 0xa2, 0x15, 0x95, 0x30, 0x80, 0x00, + 0x84, 0x4a, 0xca, 0x0a, 0x80, 0x00, + 0x30, 0x92, 0xa4, 0xaa, 0x00, 0x00, + 0x04, 0xac, 0x78, 0x15, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_7[42] = { + 0x45, 0x51, 0x15, 0x44, 0x80, 0x00, + 0x22, 0x2a, 0x8a, 0x23, 0x00, 0x00, + 0x91, 0x11, 0x85, 0x91, 0x00, 0x00, + 0x2e, 0x08, 0x32, 0x0a, 0x80, 0x00, + 0x48, 0x34, 0x58, 0x34, 0x00, 0x00, + 0x90, 0x29, 0x2c, 0x0d, 0x00, 0x00, + 0x09, 0x86, 0x43, 0xc8, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_8[48] = { + 0x20, 0x54, 0x64, 0x16, 0x00, 0x00, + 0x18, 0x88, 0xa2, 0xc2, 0x00, 0x00, + 0x84, 0x07, 0x51, 0x60, 0x80, 0x00, + 0x60, 0x48, 0x4a, 0x85, 0x00, 0x00, + 0x12, 0x82, 0x38, 0x4c, 0x00, 0x00, + 0x81, 0x41, 0x89, 0x29, 0x00, 0x00, + 0x40, 0x62, 0x07, 0x11, 0x80, 0x00, + 0x16, 0x30, 0x94, 0xb0, 0x00, 0x00 +}; + +const uint8_t kMaskRandom33_9[54] = { + 0x55, 0x51, 0x8e, 0xcc, 0x00, 0x00, + 0x22, 0x2a, 0x6a, 0x2b, 0x00, 0x00, + 0x05, 0x85, 0x36, 0x32, 0x80, 0x00, + 0x09, 0x4a, 0xd1, 0x25, 0x80, 0x00, + 0x84, 0x32, 0x55, 0x8c, 0x80, 0x00, + 0xc0, 0x0d, 0xaa, 0x27, 0x00, 0x00, + 0x20, 0xa6, 0xa5, 0x32, 0x80, 0x00, + 0x1a, 0x09, 0x62, 0x61, 0x80, 0x00, + 0x44, 0x64, 0x3c, 0x5c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom34_10[60] = { + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0xc8, 0x02, 0xe4, 0x01, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_11[66] = { + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_12[72] = { + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x35, 0x28, 0x9a, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_13[78] = { + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_14[84] = { + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0xb0, 0xde, 0xd8, 0x6f, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_15[90] = { + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_16[96] = { + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x0a, 0x1c, 0x05, 0x0e, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_17[102] = { + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x25, 0x4c, 0x12, 0xa6, 0x00, 0x00, + 0x8a, 0x66, 0x45, 0x33, 0x00, 0x00, + 0x91, 0x91, 0x48, 0xc8, 0x80, 0x00, + 0x68, 0x42, 0xb4, 0x21, 0x40, 0x00, + 0x32, 0xa4, 0x19, 0x52, 0x00, 0x00, + 0x43, 0x13, 0x21, 0x89, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0x88, 0x8e, 0x44, 0x40, 0x00, + 0x3c, 0x09, 0x1e, 0x04, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_18[108] = { + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x64, 0x16, 0x32, 0x0b, 0x00, 0x00, + 0xa2, 0xc2, 0x51, 0x61, 0x00, 0x00, + 0x51, 0x60, 0xa8, 0xb0, 0x40, 0x00, + 0x4a, 0x85, 0x25, 0x42, 0x80, 0x00, + 0x38, 0x4c, 0x1c, 0x26, 0x00, 0x00, + 0x89, 0x29, 0x44, 0x94, 0x80, 0x00, + 0x07, 0x11, 0x83, 0x88, 0xc0, 0x00, + 0x94, 0xb0, 0x4a, 0x58, 0x00, 0x00, + 0x89, 0x70, 0xf3, 0xf7, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_19[114] = { + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0xc8, 0x02, 0xe4, 0x01, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_2[12] = { + 0xce, 0xce, 0x67, 0x67, 0x00, 0x00, + 0xb9, 0x39, 0xdc, 0x9c, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom34_20[120] = { + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0xc8, 0x02, 0xe4, 0x01, 0x40, 0x00, + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x5d, 0xc5, 0xfe, 0xd8, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_21[126] = { + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0xc8, 0x02, 0xe4, 0x01, 0x40, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_22[132] = { + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0xc8, 0x02, 0xe4, 0x01, 0x40, 0x00, + 0x2a, 0xf7, 0x4f, 0xf5, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_23[138] = { + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x35, 0x28, 0x9a, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_24[144] = { + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x35, 0x28, 0x9a, 0x80, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x4c, 0xb8, 0x04, 0x74, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom34_25[150] = { + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x35, 0x28, 0x9a, 0x80, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_26[156] = { + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00, + 0x51, 0x35, 0x28, 0x9a, 0x80, 0x00, + 0x95, 0x20, 0xe9, 0xef, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom34_27[162] = { + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0xb0, 0xde, 0xd8, 0x6f, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_28[168] = { + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0xb0, 0xde, 0xd8, 0x6f, 0x40, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x10, 0x6c, 0xff, 0x60, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_29[174] = { + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0xb0, 0xde, 0xd8, 0x6f, 0x40, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_3[18] = { + 0xcd, 0xcc, 0x66, 0xe6, 0x00, 0x00, + 0x97, 0x27, 0x4b, 0x93, 0x80, 0x00, + 0xb8, 0xd1, 0xdc, 0x68, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom34_30[180] = { + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x51, 0x84, 0xa8, 0xc2, 0x40, 0x00, + 0xa2, 0x27, 0x51, 0x13, 0x80, 0x00, + 0x95, 0x51, 0xca, 0xa8, 0xc0, 0x00, + 0x4a, 0x1a, 0x25, 0x0d, 0x00, 0x00, + 0x30, 0x68, 0x18, 0x34, 0x00, 0x00, + 0x2c, 0x89, 0x16, 0x44, 0x80, 0x00, + 0xb0, 0xde, 0xd8, 0x6f, 0x40, 0x00, + 0x87, 0x93, 0x96, 0xc7, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_31[186] = { + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x0a, 0x1c, 0x05, 0x0e, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_32[192] = { + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x0a, 0x1c, 0x05, 0x0e, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0xa6, 0x27, 0xa9, 0x4a, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_33[198] = { + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x0a, 0x1c, 0x05, 0x0e, 0x00, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x25, 0x4c, 0x12, 0xa6, 0x00, 0x00, + 0x8a, 0x66, 0x45, 0x33, 0x00, 0x00, + 0x91, 0x91, 0x48, 0xc8, 0x80, 0x00, + 0x68, 0x42, 0xb4, 0x21, 0x40, 0x00, + 0x32, 0xa4, 0x19, 0x52, 0x00, 0x00, + 0x43, 0x13, 0x21, 0x89, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0x88, 0x8e, 0x44, 0x40, 0x00, + 0x3c, 0x09, 0x1e, 0x04, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_34[204] = { + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x25, 0x4c, 0x12, 0xa6, 0x00, 0x00, + 0x8a, 0x66, 0x45, 0x33, 0x00, 0x00, + 0x91, 0x91, 0x48, 0xc8, 0x80, 0x00, + 0x68, 0x42, 0xb4, 0x21, 0x40, 0x00, + 0x32, 0xa4, 0x19, 0x52, 0x00, 0x00, + 0x43, 0x13, 0x21, 0x89, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0x88, 0x8e, 0x44, 0x40, 0x00, + 0x3c, 0x09, 0x1e, 0x04, 0x80, 0x00, + 0x25, 0x2c, 0x12, 0x96, 0x00, 0x00, + 0x8a, 0x91, 0x45, 0x48, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xe0, 0x40, 0x00, + 0x68, 0x06, 0xb4, 0x03, 0x40, 0x00, + 0x32, 0xc8, 0x19, 0x64, 0x00, 0x00, + 0x43, 0x45, 0x21, 0xa2, 0x80, 0x00, + 0xc4, 0x30, 0xe2, 0x18, 0x40, 0x00, + 0x1c, 0xa2, 0x0e, 0x51, 0x00, 0x00, + 0x15, 0x8c, 0x0a, 0xc6, 0x00, 0x00, + 0x8a, 0x47, 0x45, 0x23, 0x80, 0x00, + 0x25, 0x81, 0x92, 0xc0, 0xc0, 0x00, + 0x62, 0x12, 0xb1, 0x09, 0x40, 0x00, + 0x58, 0x58, 0x2c, 0x2c, 0x00, 0x00, + 0x0e, 0x28, 0x87, 0x14, 0x40, 0x00, + 0x83, 0x34, 0x41, 0x9a, 0x00, 0x00, + 0x0a, 0x1c, 0x05, 0x0e, 0x00, 0x00, + 0x30, 0x3c, 0xb3, 0xe6, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_4[24] = { + 0xca, 0xec, 0x65, 0x76, 0x00, 0x00, + 0xa9, 0x67, 0x54, 0xb3, 0x80, 0x00, + 0x3a, 0xb1, 0x9d, 0x58, 0xc0, 0x00, + 0x55, 0x5a, 0xaa, 0xad, 0x40, 0x00 +}; + +const uint8_t kMaskRandom34_5[30] = { + 0x55, 0x44, 0xaa, 0xa2, 0x40, 0x00, + 0x2a, 0x66, 0x15, 0x33, 0x00, 0x00, + 0x25, 0xa1, 0x92, 0xd0, 0xc0, 0x00, + 0xe2, 0x12, 0xf1, 0x09, 0x40, 0x00, + 0x99, 0x98, 0x4c, 0xcc, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_6[36] = { + 0xd1, 0x4c, 0x68, 0xa6, 0x00, 0x00, + 0xa2, 0xc5, 0x51, 0x62, 0x80, 0x00, + 0x95, 0x30, 0xca, 0x98, 0x40, 0x00, + 0xca, 0x0a, 0xe5, 0x05, 0x40, 0x00, + 0xa4, 0xaa, 0x52, 0x55, 0x00, 0x00, + 0x78, 0x15, 0x3c, 0x0a, 0x80, 0x00 +}; + +const uint8_t kMaskRandom34_7[42] = { + 0x15, 0x44, 0x8a, 0xa2, 0x40, 0x00, + 0x8a, 0x23, 0x45, 0x11, 0x80, 0x00, + 0x85, 0x91, 0x42, 0xc8, 0x80, 0x00, + 0x32, 0x0a, 0x99, 0x05, 0x40, 0x00, + 0x58, 0x34, 0x2c, 0x1a, 0x00, 0x00, + 0x2c, 0x0d, 0x16, 0x06, 0x80, 0x00, + 0x43, 0xc8, 0x21, 0xe4, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_8[48] = { + 0x64, 0x16, 0x32, 0x0b, 0x00, 0x00, + 0xa2, 0xc2, 0x51, 0x61, 0x00, 0x00, + 0x51, 0x60, 0xa8, 0xb0, 0x40, 0x00, + 0x4a, 0x85, 0x25, 0x42, 0x80, 0x00, + 0x38, 0x4c, 0x1c, 0x26, 0x00, 0x00, + 0x89, 0x29, 0x44, 0x94, 0x80, 0x00, + 0x07, 0x11, 0x83, 0x88, 0xc0, 0x00, + 0x94, 0xb0, 0x4a, 0x58, 0x00, 0x00 +}; + +const uint8_t kMaskRandom34_9[54] = { + 0x8e, 0xcc, 0x47, 0x66, 0x00, 0x00, + 0x6a, 0x2b, 0x35, 0x15, 0x80, 0x00, + 0x36, 0x32, 0x9b, 0x19, 0x40, 0x00, + 0xd1, 0x25, 0xe8, 0x92, 0xc0, 0x00, + 0x55, 0x8c, 0xaa, 0xc6, 0x40, 0x00, + 0xaa, 0x27, 0x55, 0x13, 0x80, 0x00, + 0xa5, 0x32, 0xd2, 0x99, 0x40, 0x00, + 0x62, 0x61, 0xb1, 0x30, 0xc0, 0x00, + 0x3c, 0x5c, 0x1e, 0x2e, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom35_10[60] = { + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x8e, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x6a, 0x2b, 0x15, 0x8a, 0xc0, 0x00, + 0x36, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0xd1, 0x25, 0x92, 0xc9, 0x60, 0x00, + 0xc8, 0x02, 0xfe, 0xce, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom35_11[66] = { + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00 +}; + +const uint8_t kMaskRandom35_12[72] = { + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x35, 0x2d, 0x86, 0x20, 0x00 +}; + +const uint8_t kMaskRandom35_13[78] = { + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_14[84] = { + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0xb0, 0xde, 0xbf, 0xa7, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom35_15[90] = { + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00 +}; + +const uint8_t kMaskRandom35_16[96] = { + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x0a, 0x1c, 0x77, 0xf9, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_17[102] = { + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x25, 0x4c, 0x26, 0x13, 0x00, 0x00, + 0x8a, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x91, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x68, 0x42, 0xa1, 0x50, 0xa0, 0x00, + 0x32, 0xa4, 0x52, 0x29, 0x00, 0x00, + 0x43, 0x13, 0x09, 0x84, 0xc0, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0x88, 0xc4, 0x62, 0x20, 0x00, + 0x3c, 0x09, 0x04, 0x82, 0x40, 0x00 +}; + +const uint8_t kMaskRandom35_18[108] = { + 0x8e, 0xcc, 0x22, 0x51, 0x20, 0x00, + 0x6a, 0x2b, 0x33, 0x13, 0x00, 0x00, + 0x36, 0x32, 0xc8, 0x24, 0xa0, 0x00, + 0xd1, 0x25, 0x80, 0xd2, 0xc0, 0x00, + 0x55, 0x8c, 0x87, 0x09, 0x40, 0x00, + 0xaa, 0x27, 0x09, 0x85, 0x80, 0x00, + 0xa5, 0x32, 0x90, 0x68, 0x20, 0x00, + 0x62, 0x61, 0xe1, 0x28, 0x80, 0x00, + 0x3c, 0x5c, 0x14, 0x86, 0x40, 0x00, + 0x64, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0xa2, 0xc2, 0x61, 0x30, 0x80, 0x00, + 0x51, 0x60, 0xb0, 0x58, 0x20, 0x00, + 0x4a, 0x85, 0x42, 0xa1, 0x40, 0x00, + 0x38, 0x4c, 0x26, 0x13, 0x00, 0x00, + 0x89, 0x29, 0x14, 0x8a, 0x40, 0x00, + 0x07, 0x11, 0x88, 0xc4, 0x60, 0x00, + 0x94, 0xb0, 0x58, 0x2c, 0x00, 0x00, + 0x40, 0xc9, 0x65, 0xbe, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom35_19[114] = { + 0x8e, 0xcc, 0x22, 0x51, 0x20, 0x00, + 0x6a, 0x2b, 0x33, 0x13, 0x00, 0x00, + 0x36, 0x32, 0xc8, 0x24, 0xa0, 0x00, + 0xd1, 0x25, 0x80, 0xd2, 0xc0, 0x00, + 0x55, 0x8c, 0x87, 0x09, 0x40, 0x00, + 0xaa, 0x27, 0x09, 0x85, 0x80, 0x00, + 0xa5, 0x32, 0x90, 0x68, 0x20, 0x00, + 0x62, 0x61, 0xe1, 0x28, 0x80, 0x00, + 0x3c, 0x5c, 0x14, 0x86, 0x40, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x8e, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x6a, 0x2b, 0x15, 0x8a, 0xc0, 0x00, + 0x36, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0xd1, 0x25, 0x92, 0xc9, 0x60, 0x00, + 0xc8, 0x02, 0xfe, 0xce, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom35_2[12] = { + 0xce, 0xce, 0x67, 0x33, 0x80, 0x00, + 0xb9, 0x39, 0x9c, 0xce, 0x60, 0x00 +}; + +const uint8_t kMaskRandom35_20[120] = { + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x8e, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x6a, 0x2b, 0x15, 0x8a, 0xc0, 0x00, + 0x36, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0xd1, 0x25, 0x92, 0xc9, 0x60, 0x00, + 0xc8, 0x02, 0xfe, 0xce, 0xe0, 0x00, + 0x8e, 0xcc, 0x22, 0x51, 0x20, 0x00, + 0x6a, 0x2b, 0x33, 0x13, 0x00, 0x00, + 0x36, 0x32, 0xc8, 0x24, 0xa0, 0x00, + 0xd1, 0x25, 0x80, 0xd2, 0xc0, 0x00, + 0x55, 0x8c, 0x87, 0x09, 0x40, 0x00, + 0xaa, 0x27, 0x09, 0x85, 0x80, 0x00, + 0xa5, 0x32, 0x90, 0x68, 0x20, 0x00, + 0x62, 0x61, 0xe1, 0x28, 0x80, 0x00, + 0x3c, 0x5c, 0x14, 0x86, 0x40, 0x00, + 0x63, 0x36, 0x5c, 0xd3, 0x80, 0x00 +}; + +const uint8_t kMaskRandom35_21[126] = { + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x8e, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x6a, 0x2b, 0x15, 0x8a, 0xc0, 0x00, + 0x36, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0xd1, 0x25, 0x92, 0xc9, 0x60, 0x00, + 0xc8, 0x02, 0xfe, 0xce, 0xe0, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00 +}; + +const uint8_t kMaskRandom35_22[132] = { + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x8e, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x6a, 0x2b, 0x15, 0x8a, 0xc0, 0x00, + 0x36, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0xd1, 0x25, 0x92, 0xc9, 0x60, 0x00, + 0xc8, 0x02, 0xfe, 0xce, 0xe0, 0x00, + 0x84, 0xc7, 0xbc, 0xcc, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_23[138] = { + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x35, 0x2d, 0x86, 0x20, 0x00 +}; + +const uint8_t kMaskRandom35_24[144] = { + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x35, 0x2d, 0x86, 0x20, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x0d, 0xfb, 0x06, 0x89, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_25[150] = { + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x35, 0x2d, 0x86, 0x20, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_26[156] = { + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x55, 0x8c, 0xc6, 0x63, 0x20, 0x00, + 0xaa, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0xa5, 0x32, 0x99, 0x4c, 0xa0, 0x00, + 0x62, 0x61, 0xb0, 0xd8, 0x60, 0x00, + 0x3c, 0x5c, 0x2e, 0x17, 0x00, 0x00, + 0x51, 0x35, 0x2d, 0x86, 0x20, 0x00, + 0xc4, 0x57, 0x70, 0x47, 0x40, 0x00 +}; + +const uint8_t kMaskRandom35_27[162] = { + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0xb0, 0xde, 0xbf, 0xa7, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom35_28[168] = { + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0xb0, 0xde, 0xbf, 0xa7, 0xe0, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x34, 0x4a, 0x80, 0x94, 0x40, 0x00 +}; + +const uint8_t kMaskRandom35_29[174] = { + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0xb0, 0xde, 0xbf, 0xa7, 0xe0, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00 +}; + +const uint8_t kMaskRandom35_3[18] = { + 0xcd, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x97, 0x27, 0x13, 0x8a, 0xc0, 0x00, + 0xb8, 0xd1, 0xc9, 0x64, 0xa0, 0x00 +}; + +const uint8_t kMaskRandom35_30[180] = { + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x51, 0x84, 0xc2, 0x61, 0x20, 0x00, + 0xa2, 0x27, 0x13, 0x89, 0xc0, 0x00, + 0x95, 0x51, 0xa8, 0xd4, 0x60, 0x00, + 0x4a, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x30, 0x68, 0x34, 0x1a, 0x00, 0x00, + 0x2c, 0x89, 0x44, 0xa2, 0x40, 0x00, + 0xb0, 0xde, 0xbf, 0xa7, 0xe0, 0x00, + 0x32, 0x1b, 0x9f, 0x09, 0x20, 0x00 +}; + +const uint8_t kMaskRandom35_31[186] = { + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x0a, 0x1c, 0x77, 0xf9, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_32[192] = { + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x0a, 0x1c, 0x77, 0xf9, 0x00, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0xeb, 0x31, 0x7b, 0x80, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_33[198] = { + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x0a, 0x1c, 0x77, 0xf9, 0x00, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x25, 0x4c, 0x26, 0x13, 0x00, 0x00, + 0x8a, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x91, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x68, 0x42, 0xa1, 0x50, 0xa0, 0x00, + 0x32, 0xa4, 0x52, 0x29, 0x00, 0x00, + 0x43, 0x13, 0x09, 0x84, 0xc0, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0x88, 0xc4, 0x62, 0x20, 0x00, + 0x3c, 0x09, 0x04, 0x82, 0x40, 0x00 +}; + +const uint8_t kMaskRandom35_34[204] = { + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x25, 0x4c, 0x26, 0x13, 0x00, 0x00, + 0x8a, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x91, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x68, 0x42, 0xa1, 0x50, 0xa0, 0x00, + 0x32, 0xa4, 0x52, 0x29, 0x00, 0x00, + 0x43, 0x13, 0x09, 0x84, 0xc0, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0x88, 0xc4, 0x62, 0x20, 0x00, + 0x3c, 0x09, 0x04, 0x82, 0x40, 0x00, + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x15, 0x8c, 0x46, 0x23, 0x00, 0x00, + 0x8a, 0x47, 0x23, 0x91, 0xc0, 0x00, + 0x25, 0x81, 0xc0, 0xe0, 0x60, 0x00, + 0x62, 0x12, 0x89, 0x44, 0xa0, 0x00, + 0x58, 0x58, 0x2c, 0x16, 0x00, 0x00, + 0x0e, 0x28, 0x94, 0x4a, 0x20, 0x00, + 0x83, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x0a, 0x1c, 0x77, 0xf9, 0x00, 0x00, + 0x70, 0x07, 0xcd, 0x8c, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom35_35[210] = { + 0x25, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x8a, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x91, 0xc0, 0xe0, 0x70, 0x20, 0x00, + 0x68, 0x06, 0x83, 0x41, 0xa0, 0x00, + 0x32, 0xc8, 0x64, 0x32, 0x00, 0x00, + 0x43, 0x45, 0x22, 0x91, 0x40, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x51, 0x28, 0x80, 0x00, + 0x25, 0x4c, 0x26, 0x13, 0x00, 0x00, + 0x8a, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x91, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x68, 0x42, 0xa1, 0x50, 0xa0, 0x00, + 0x32, 0xa4, 0x52, 0x29, 0x00, 0x00, + 0x43, 0x13, 0x09, 0x84, 0xc0, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0x88, 0xc4, 0x62, 0x20, 0x00, + 0x3c, 0x09, 0x04, 0x82, 0x40, 0x00, + 0x25, 0x2c, 0x26, 0x13, 0x00, 0x00, + 0x8a, 0x91, 0x33, 0x19, 0x80, 0x00, + 0x91, 0xc0, 0xc8, 0xa4, 0x40, 0x00, + 0x68, 0x06, 0xa1, 0x50, 0xa0, 0x00, + 0x32, 0xc8, 0x52, 0x29, 0x00, 0x00, + 0x43, 0x45, 0x09, 0x84, 0xc0, 0x00, + 0xc4, 0x30, 0x98, 0x4c, 0x20, 0x00, + 0x1c, 0xa2, 0x44, 0x62, 0x20, 0x00, + 0x25, 0x4c, 0x04, 0x82, 0x40, 0x00, + 0x8a, 0x66, 0x16, 0x0b, 0x00, 0x00, + 0x91, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x68, 0x42, 0xe0, 0x70, 0x20, 0x00, + 0x32, 0xa4, 0x03, 0x41, 0xa0, 0x00, + 0x43, 0x13, 0x64, 0x32, 0x00, 0x00, + 0xc4, 0x30, 0xa2, 0x91, 0x40, 0x00, + 0x1c, 0x88, 0x98, 0x4c, 0x20, 0x00, + 0x3c, 0x09, 0x51, 0x28, 0x80, 0x00, + 0xc2, 0x1c, 0x68, 0x01, 0xa0, 0x00 +}; + +const uint8_t kMaskRandom35_4[24] = { + 0xca, 0xec, 0x76, 0x3b, 0x00, 0x00, + 0xa9, 0x67, 0x33, 0x99, 0xc0, 0x00, + 0x3a, 0xb1, 0xd8, 0xec, 0x60, 0x00, + 0x55, 0x5a, 0xad, 0x56, 0xa0, 0x00 +}; + +const uint8_t kMaskRandom35_5[30] = { + 0x55, 0x44, 0xa6, 0x53, 0x20, 0x00, + 0x2a, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x25, 0xa1, 0x8c, 0xe8, 0x60, 0x00, + 0xe2, 0x12, 0xce, 0x44, 0xa0, 0x00, + 0x99, 0x98, 0x71, 0xa6, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_6[36] = { + 0xd1, 0x4c, 0x66, 0x13, 0x00, 0x00, + 0xa2, 0xc5, 0x22, 0xb1, 0x40, 0x00, + 0x95, 0x30, 0xd8, 0x4c, 0x20, 0x00, + 0xca, 0x0a, 0xc5, 0x42, 0xa0, 0x00, + 0xa4, 0xaa, 0x14, 0xa9, 0x80, 0x00, + 0x78, 0x15, 0x53, 0x05, 0x40, 0x00 +}; + +const uint8_t kMaskRandom35_7[42] = { + 0x15, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8a, 0x23, 0x11, 0x88, 0xc0, 0x00, + 0x85, 0x91, 0x48, 0xa4, 0x40, 0x00, + 0x32, 0x0a, 0x85, 0x42, 0xa0, 0x00, + 0x58, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x2c, 0x0d, 0x05, 0x83, 0x40, 0x00, + 0x43, 0xc8, 0x70, 0x32, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_8[48] = { + 0x64, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0xa2, 0xc2, 0x61, 0x30, 0x80, 0x00, + 0x51, 0x60, 0xb0, 0x58, 0x20, 0x00, + 0x4a, 0x85, 0x42, 0xa1, 0x40, 0x00, + 0x38, 0x4c, 0x26, 0x13, 0x00, 0x00, + 0x89, 0x29, 0x14, 0x8a, 0x40, 0x00, + 0x07, 0x11, 0x88, 0xc4, 0x60, 0x00, + 0x94, 0xb0, 0x58, 0x2c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom35_9[54] = { + 0x8e, 0xcc, 0x22, 0x51, 0x20, 0x00, + 0x6a, 0x2b, 0x33, 0x13, 0x00, 0x00, + 0x36, 0x32, 0xc8, 0x24, 0xa0, 0x00, + 0xd1, 0x25, 0x80, 0xd2, 0xc0, 0x00, + 0x55, 0x8c, 0x87, 0x09, 0x40, 0x00, + 0xaa, 0x27, 0x09, 0x85, 0x80, 0x00, + 0xa5, 0x32, 0x90, 0x68, 0x20, 0x00, + 0x62, 0x61, 0xe1, 0x28, 0x80, 0x00, + 0x3c, 0x5c, 0x14, 0x86, 0x40, 0x00 +}; + +const uint8_t kMaskRandom36_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 +}; + +const uint8_t kMaskRandom36_10[60] = { + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0xcc, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x2b, 0x15, 0x8a, 0xc5, 0x60, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x25, 0x92, 0xc9, 0x64, 0xb0, 0x00, + 0xfd, 0x9d, 0xff, 0x67, 0x70, 0x00 +}; + +const uint8_t kMaskRandom36_11[66] = { + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00 +}; + +const uint8_t kMaskRandom36_12[72] = { + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x5b, 0x0c, 0x56, 0xc3, 0x10, 0x00 +}; + +const uint8_t kMaskRandom36_13[78] = { + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00 +}; + +const uint8_t kMaskRandom36_14[84] = { + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x7f, 0x4f, 0xdf, 0xd3, 0xf0, 0x00 +}; + +const uint8_t kMaskRandom36_15[90] = { + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00 +}; + +const uint8_t kMaskRandom36_16[96] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0xef, 0xf2, 0x3b, 0xfc, 0x80, 0x00 +}; + +const uint8_t kMaskRandom36_17[102] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00 +}; + +const uint8_t kMaskRandom36_18[108] = { + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0xd0, 0x03, 0x74, 0x00, 0xd0, 0x00 +}; + +const uint8_t kMaskRandom36_19[114] = { + 0x44, 0xa2, 0x51, 0x28, 0x90, 0x00, + 0x66, 0x26, 0x19, 0x89, 0x80, 0x00, + 0x90, 0x49, 0x64, 0x12, 0x50, 0x00, + 0x01, 0xa5, 0x80, 0x69, 0x60, 0x00, + 0x0e, 0x12, 0x83, 0x84, 0xa0, 0x00, + 0x13, 0x0b, 0x04, 0xc2, 0xc0, 0x00, + 0x20, 0xd0, 0x48, 0x34, 0x10, 0x00, + 0xc2, 0x51, 0x30, 0x94, 0x40, 0x00, + 0x29, 0x0c, 0x8a, 0x43, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0xcc, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x2b, 0x15, 0x8a, 0xc5, 0x60, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x25, 0x92, 0xc9, 0x64, 0xb0, 0x00, + 0xfd, 0x9d, 0xff, 0x67, 0x70, 0x00 +}; + +const uint8_t kMaskRandom36_2[12] = { + 0xce, 0x67, 0x33, 0x99, 0xc0, 0x00, + 0x39, 0x9c, 0xce, 0x67, 0x30, 0x00 +}; + +const uint8_t kMaskRandom36_20[120] = { + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0xcc, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x2b, 0x15, 0x8a, 0xc5, 0x60, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x25, 0x92, 0xc9, 0x64, 0xb0, 0x00, + 0xfd, 0x9d, 0xff, 0x67, 0x70, 0x00, + 0x44, 0xa2, 0x51, 0x28, 0x90, 0x00, + 0x66, 0x26, 0x19, 0x89, 0x80, 0x00, + 0x90, 0x49, 0x64, 0x12, 0x50, 0x00, + 0x01, 0xa5, 0x80, 0x69, 0x60, 0x00, + 0x0e, 0x12, 0x83, 0x84, 0xa0, 0x00, + 0x13, 0x0b, 0x04, 0xc2, 0xc0, 0x00, + 0x20, 0xd0, 0x48, 0x34, 0x10, 0x00, + 0xc2, 0x51, 0x30, 0x94, 0x40, 0x00, + 0x29, 0x0c, 0x8a, 0x43, 0x20, 0x00, + 0x45, 0xb9, 0x08, 0x16, 0x30, 0x00 +}; + +const uint8_t kMaskRandom36_21[126] = { + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0xcc, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x2b, 0x15, 0x8a, 0xc5, 0x60, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x25, 0x92, 0xc9, 0x64, 0xb0, 0x00, + 0xfd, 0x9d, 0xff, 0x67, 0x70, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00 +}; + +const uint8_t kMaskRandom36_22[132] = { + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0xcc, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x2b, 0x15, 0x8a, 0xc5, 0x60, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x25, 0x92, 0xc9, 0x64, 0xb0, 0x00, + 0xfd, 0x9d, 0xff, 0x67, 0x70, 0x00, + 0x71, 0x04, 0xba, 0x7b, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom36_23[138] = { + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x5b, 0x0c, 0x56, 0xc3, 0x10, 0x00 +}; + +const uint8_t kMaskRandom36_24[144] = { + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x5b, 0x0c, 0x56, 0xc3, 0x10, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x76, 0x3a, 0xeb, 0x17, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom36_25[150] = { + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x5b, 0x0c, 0x56, 0xc3, 0x10, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00 +}; + +const uint8_t kMaskRandom36_26[156] = { + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x31, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x32, 0x99, 0x4c, 0xa6, 0x50, 0x00, + 0x61, 0xb0, 0xd8, 0x6c, 0x30, 0x00, + 0x5c, 0x2e, 0x17, 0x0b, 0x80, 0x00, + 0x5b, 0x0c, 0x56, 0xc3, 0x10, 0x00, + 0xec, 0x58, 0x0e, 0x6c, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom36_27[162] = { + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x7f, 0x4f, 0xdf, 0xd3, 0xf0, 0x00 +}; + +const uint8_t kMaskRandom36_28[168] = { + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x7f, 0x4f, 0xdf, 0xd3, 0xf0, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x29, 0xfd, 0x91, 0x6f, 0xd0, 0x00 +}; + +const uint8_t kMaskRandom36_29[174] = { + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x7f, 0x4f, 0xdf, 0xd3, 0xf0, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00 +}; + +const uint8_t kMaskRandom36_3[18] = { + 0xcc, 0x66, 0x33, 0x19, 0x80, 0x00, + 0x27, 0x15, 0x89, 0xc5, 0x60, 0x00, + 0x92, 0xc9, 0x64, 0xb2, 0x50, 0x00 +}; + +const uint8_t kMaskRandom36_30[180] = { + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x84, 0xc2, 0x61, 0x30, 0x90, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0xe0, 0x00, + 0x51, 0xa8, 0xd4, 0x6a, 0x30, 0x00, + 0x1a, 0x0d, 0x06, 0x83, 0x40, 0x00, + 0x68, 0x34, 0x1a, 0x0d, 0x00, 0x00, + 0x89, 0x44, 0xa2, 0x51, 0x20, 0x00, + 0x7f, 0x4f, 0xdf, 0xd3, 0xf0, 0x00, + 0xc5, 0x38, 0xbb, 0x98, 0x80, 0x00 +}; + +const uint8_t kMaskRandom36_31[186] = { + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0xef, 0xf2, 0x3b, 0xfc, 0x80, 0x00 +}; + +const uint8_t kMaskRandom36_32[192] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0xef, 0xf2, 0x3b, 0xfc, 0x80, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x3a, 0x28, 0x9c, 0x2f, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom36_33[198] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0xef, 0xf2, 0x3b, 0xfc, 0x80, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00 +}; + +const uint8_t kMaskRandom36_34[204] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x8c, 0x46, 0x23, 0x11, 0x80, 0x00, + 0x47, 0x23, 0x91, 0xc8, 0xe0, 0x00, + 0x81, 0xc0, 0xe0, 0x70, 0x30, 0x00, + 0x12, 0x89, 0x44, 0xa2, 0x50, 0x00, + 0x58, 0x2c, 0x16, 0x0b, 0x00, 0x00, + 0x28, 0x94, 0x4a, 0x25, 0x10, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0xef, 0xf2, 0x3b, 0xfc, 0x80, 0x00, + 0xf7, 0x5e, 0x66, 0x5b, 0x60, 0x00 +}; + +const uint8_t kMaskRandom36_35[210] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0xd0, 0x03, 0x74, 0x00, 0xd0, 0x00 +}; + +const uint8_t kMaskRandom36_36[216] = { + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0xd0, 0x03, 0x74, 0x00, 0xd0, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0xc0, 0xe0, 0x70, 0x38, 0x10, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xd0, 0x00, + 0xc8, 0x64, 0x32, 0x19, 0x00, 0x00, + 0x45, 0x22, 0x91, 0x48, 0xa0, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0xa2, 0x51, 0x28, 0x94, 0x40, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x42, 0xa1, 0x50, 0xa8, 0x50, 0x00, + 0xa4, 0x52, 0x29, 0x14, 0x80, 0x00, + 0x13, 0x09, 0x84, 0xc2, 0x60, 0x00, + 0x30, 0x98, 0x4c, 0x26, 0x10, 0x00, + 0x88, 0xc4, 0x62, 0x31, 0x10, 0x00, + 0x09, 0x04, 0x82, 0x41, 0x20, 0x00, + 0xa4, 0x9c, 0x31, 0x13, 0x80, 0x00 +}; + +const uint8_t kMaskRandom36_4[24] = { + 0xec, 0x76, 0x3b, 0x1d, 0x80, 0x00, + 0x67, 0x33, 0x99, 0xcc, 0xe0, 0x00, + 0xb1, 0xd8, 0xec, 0x76, 0x30, 0x00, + 0x5a, 0xad, 0x56, 0xab, 0x50, 0x00 +}; + +const uint8_t kMaskRandom36_5[30] = { + 0x4c, 0xa6, 0x53, 0x29, 0x90, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0xc0, 0x00, + 0x19, 0xd0, 0xc6, 0x74, 0x30, 0x00, + 0x9c, 0x89, 0x67, 0x22, 0x50, 0x00, + 0xe3, 0x4c, 0x38, 0xd3, 0x00, 0x00 +}; + +const uint8_t kMaskRandom36_6[36] = { + 0xcc, 0x26, 0x33, 0x09, 0x80, 0x00, + 0x45, 0x62, 0x91, 0x58, 0xa0, 0x00, + 0xb0, 0x98, 0x6c, 0x26, 0x10, 0x00, + 0x8a, 0x85, 0x62, 0xa1, 0x50, 0x00, + 0x29, 0x53, 0x0a, 0x54, 0xc0, 0x00, + 0xa6, 0x0a, 0xa9, 0x82, 0xa0, 0x00 +}; + +const uint8_t kMaskRandom36_7[42] = { + 0x44, 0xa2, 0x51, 0x28, 0x90, 0x00, + 0x23, 0x11, 0x88, 0xc4, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x52, 0x20, 0x00, + 0x0a, 0x85, 0x42, 0xa1, 0x50, 0x00, + 0x34, 0x1a, 0x0d, 0x06, 0x80, 0x00, + 0x0b, 0x06, 0x82, 0xc1, 0xa0, 0x00, + 0xe0, 0x64, 0x38, 0x19, 0x00, 0x00 +}; + +const uint8_t kMaskRandom36_8[48] = { + 0x16, 0x0b, 0x05, 0x82, 0xc0, 0x00, + 0xc2, 0x61, 0x30, 0x98, 0x40, 0x00, + 0x60, 0xb0, 0x58, 0x2c, 0x10, 0x00, + 0x85, 0x42, 0xa1, 0x50, 0xa0, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0x80, 0x00, + 0x29, 0x14, 0x8a, 0x45, 0x20, 0x00, + 0x11, 0x88, 0xc4, 0x62, 0x30, 0x00, + 0xb0, 0x58, 0x2c, 0x16, 0x00, 0x00 +}; + +const uint8_t kMaskRandom36_9[54] = { + 0x44, 0xa2, 0x51, 0x28, 0x90, 0x00, + 0x66, 0x26, 0x19, 0x89, 0x80, 0x00, + 0x90, 0x49, 0x64, 0x12, 0x50, 0x00, + 0x01, 0xa5, 0x80, 0x69, 0x60, 0x00, + 0x0e, 0x12, 0x83, 0x84, 0xa0, 0x00, + 0x13, 0x0b, 0x04, 0xc2, 0xc0, 0x00, + 0x20, 0xd0, 0x48, 0x34, 0x10, 0x00, + 0xc2, 0x51, 0x30, 0x94, 0x40, 0x00, + 0x29, 0x0c, 0x8a, 0x43, 0x20, 0x00 +}; + +const uint8_t kMaskRandom37_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 +}; + +const uint8_t kMaskRandom37_10[60] = { + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0xcc, 0x66, 0x33, 0x1d, 0x40, 0x00, + 0x2b, 0x15, 0x8a, 0xc6, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xb4, 0x98, 0x00, + 0x25, 0x92, 0xc9, 0x63, 0xa8, 0x00, + 0xfd, 0x9d, 0xd4, 0x22, 0x30, 0x00 +}; + +const uint8_t kMaskRandom37_11[66] = { + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom37_12[72] = { + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x5b, 0x0c, 0x64, 0x32, 0x20, 0x00 +}; + +const uint8_t kMaskRandom37_13[78] = { + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00 +}; + +const uint8_t kMaskRandom37_14[84] = { + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x7f, 0x4f, 0xdb, 0x89, 0xd8, 0x00 +}; + +const uint8_t kMaskRandom37_15[90] = { + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00 +}; + +const uint8_t kMaskRandom37_16[96] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0xef, 0xf2, 0x1f, 0x9d, 0x78, 0x00 +}; + +const uint8_t kMaskRandom37_17[102] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00 +}; + +const uint8_t kMaskRandom37_18[108] = { + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0xd0, 0x03, 0x54, 0x65, 0xc8, 0x00 +}; + +const uint8_t kMaskRandom37_19[114] = { + 0x44, 0xa2, 0x51, 0x29, 0xc0, 0x00, + 0x66, 0x26, 0x19, 0x9c, 0x20, 0x00, + 0x90, 0x49, 0x44, 0xb0, 0x38, 0x00, + 0x01, 0xa5, 0xb0, 0xc4, 0x28, 0x00, + 0x0e, 0x12, 0xa3, 0x0a, 0x50, 0x00, + 0x13, 0x0b, 0x04, 0x56, 0xc0, 0x00, + 0x20, 0xd0, 0x48, 0x64, 0xd0, 0x00, + 0xc2, 0x51, 0x28, 0x8b, 0x00, 0x00, + 0x29, 0x0c, 0x86, 0x03, 0x38, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0xcc, 0x66, 0x33, 0x1d, 0x40, 0x00, + 0x2b, 0x15, 0x8a, 0xc6, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xb4, 0x98, 0x00, + 0x25, 0x92, 0xc9, 0x63, 0xa8, 0x00, + 0xfd, 0x9d, 0xd4, 0x22, 0x30, 0x00 +}; + +const uint8_t kMaskRandom37_2[12] = { + 0xce, 0x67, 0x33, 0x9d, 0xc0, 0x00, + 0x39, 0x9c, 0xce, 0x73, 0x38, 0x00 +}; + +const uint8_t kMaskRandom37_20[120] = { + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0xcc, 0x66, 0x33, 0x1d, 0x40, 0x00, + 0x2b, 0x15, 0x8a, 0xc6, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xb4, 0x98, 0x00, + 0x25, 0x92, 0xc9, 0x63, 0xa8, 0x00, + 0xfd, 0x9d, 0xd4, 0x22, 0x30, 0x00, + 0x44, 0xa2, 0x51, 0x29, 0xc0, 0x00, + 0x66, 0x26, 0x19, 0x9c, 0x20, 0x00, + 0x90, 0x49, 0x44, 0xb0, 0x38, 0x00, + 0x01, 0xa5, 0xb0, 0xc4, 0x28, 0x00, + 0x0e, 0x12, 0xa3, 0x0a, 0x50, 0x00, + 0x13, 0x0b, 0x04, 0x56, 0xc0, 0x00, + 0x20, 0xd0, 0x48, 0x64, 0xd0, 0x00, + 0xc2, 0x51, 0x28, 0x8b, 0x00, 0x00, + 0x29, 0x0c, 0x86, 0x03, 0x38, 0x00, + 0xe5, 0x44, 0xda, 0x3a, 0xc8, 0x00 +}; + +const uint8_t kMaskRandom37_21[126] = { + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0xcc, 0x66, 0x33, 0x1d, 0x40, 0x00, + 0x2b, 0x15, 0x8a, 0xc6, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xb4, 0x98, 0x00, + 0x25, 0x92, 0xc9, 0x63, 0xa8, 0x00, + 0xfd, 0x9d, 0xd4, 0x22, 0x30, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00 +}; + +const uint8_t kMaskRandom37_22[132] = { + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0xcc, 0x66, 0x33, 0x1d, 0x40, 0x00, + 0x2b, 0x15, 0x8a, 0xc6, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xb4, 0x98, 0x00, + 0x25, 0x92, 0xc9, 0x63, 0xa8, 0x00, + 0xfd, 0x9d, 0xd4, 0x22, 0x30, 0x00, + 0xe4, 0xd3, 0xff, 0x5a, 0x28, 0x00 +}; + +const uint8_t kMaskRandom37_23[138] = { + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x5b, 0x0c, 0x64, 0x32, 0x20, 0x00 +}; + +const uint8_t kMaskRandom37_24[144] = { + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x5b, 0x0c, 0x64, 0x32, 0x20, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0xad, 0x58, 0xb2, 0x36, 0x68, 0x00 +}; + +const uint8_t kMaskRandom37_25[150] = { + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x5b, 0x0c, 0x64, 0x32, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00 +}; + +const uint8_t kMaskRandom37_26[156] = { + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0xc6, 0x63, 0x38, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc4, 0x70, 0x00, + 0x32, 0x99, 0x4c, 0xa3, 0x48, 0x00, + 0x61, 0xb0, 0xd8, 0x64, 0x98, 0x00, + 0x5c, 0x2e, 0x17, 0x0e, 0x20, 0x00, + 0x5b, 0x0c, 0x64, 0x32, 0x20, 0x00, + 0x7f, 0xb2, 0x5a, 0xaa, 0x20, 0x00 +}; + +const uint8_t kMaskRandom37_27[162] = { + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x7f, 0x4f, 0xdb, 0x89, 0xd8, 0x00 +}; + +const uint8_t kMaskRandom37_28[168] = { + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x7f, 0x4f, 0xdb, 0x89, 0xd8, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x7b, 0xc4, 0x24, 0xbf, 0x10, 0x00 +}; + +const uint8_t kMaskRandom37_29[174] = { + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x7f, 0x4f, 0xdb, 0x89, 0xd8, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00 +}; + +const uint8_t kMaskRandom37_3[18] = { + 0xcc, 0x66, 0x33, 0x19, 0xc0, 0x00, + 0x27, 0x15, 0x89, 0xcb, 0x30, 0x00, + 0x92, 0xc9, 0x64, 0xb4, 0x98, 0x00 +}; + +const uint8_t kMaskRandom37_30[180] = { + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x84, 0xc2, 0x61, 0x21, 0xc0, 0x00, + 0x27, 0x13, 0x89, 0xc6, 0x60, 0x00, + 0x51, 0xa8, 0xd4, 0x62, 0x18, 0x00, + 0x1a, 0x0d, 0x06, 0x88, 0xa8, 0x00, + 0x68, 0x34, 0x1a, 0x11, 0x10, 0x00, + 0x89, 0x44, 0xa2, 0x5c, 0x00, 0x00, + 0x7f, 0x4f, 0xdb, 0x89, 0xd8, 0x00, + 0x1d, 0x8e, 0x11, 0xb0, 0xe8, 0x00 +}; + +const uint8_t kMaskRandom37_31[186] = { + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0xef, 0xf2, 0x1f, 0x9d, 0x78, 0x00 +}; + +const uint8_t kMaskRandom37_32[192] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0xef, 0xf2, 0x1f, 0x9d, 0x78, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0xf7, 0x95, 0x57, 0x8c, 0x40, 0x00 +}; + +const uint8_t kMaskRandom37_33[198] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0xef, 0xf2, 0x1f, 0x9d, 0x78, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00 +}; + +const uint8_t kMaskRandom37_34[204] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x8c, 0x46, 0x23, 0x08, 0xc0, 0x00, + 0x47, 0x23, 0x91, 0xc6, 0x60, 0x00, + 0x81, 0xc0, 0xe0, 0x62, 0x18, 0x00, + 0x12, 0x89, 0x44, 0xa1, 0x88, 0x00, + 0x58, 0x2c, 0x16, 0x05, 0x10, 0x00, + 0x28, 0x94, 0x4a, 0x32, 0x80, 0x00, + 0x34, 0x1a, 0x0d, 0x18, 0x20, 0x00, + 0xef, 0xf2, 0x1f, 0x9d, 0x78, 0x00, + 0x31, 0x9c, 0xfb, 0x37, 0xc0, 0x00 +}; + +const uint8_t kMaskRandom37_35[210] = { + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0xd0, 0x03, 0x54, 0x65, 0xc8, 0x00 +}; + +const uint8_t kMaskRandom37_36[216] = { + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0xd0, 0x03, 0x54, 0x65, 0xc8, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0xc3, 0xc7, 0xce, 0xd8, 0x50, 0x00 +}; + +const uint8_t kMaskRandom37_37[222] = { + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0x2c, 0x16, 0x0b, 0x05, 0x80, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x30, 0x00, + 0xc0, 0xe0, 0x70, 0x34, 0x08, 0x00, + 0x06, 0x83, 0x41, 0xa0, 0xa8, 0x00, + 0xc8, 0x64, 0x32, 0x03, 0x10, 0x00, + 0x45, 0x22, 0x91, 0x58, 0x40, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0x50, 0x00, + 0xa2, 0x51, 0x28, 0x8a, 0x08, 0x00, + 0xd0, 0x03, 0x54, 0x65, 0xc8, 0x00, + 0x4c, 0x26, 0x13, 0x09, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x9c, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x50, 0x38, 0x00, + 0x42, 0xa1, 0x50, 0xa4, 0x28, 0x00, + 0xa4, 0x52, 0x29, 0x0a, 0x50, 0x00, + 0x13, 0x09, 0x84, 0xd6, 0x80, 0x00, + 0x30, 0x98, 0x4c, 0x24, 0xd0, 0x00, + 0x88, 0xc4, 0x62, 0x2b, 0x08, 0x00, + 0x09, 0x04, 0x82, 0x43, 0x30, 0x00, + 0x2c, 0x16, 0x13, 0x09, 0x80, 0x00, + 0x91, 0x48, 0x99, 0x8a, 0x20, 0x00, + 0xc0, 0xe0, 0x64, 0x54, 0x08, 0x00, + 0x06, 0x83, 0x50, 0xa0, 0x98, 0x00, + 0xc8, 0x64, 0x29, 0x00, 0x70, 0x00, + 0x45, 0x22, 0x84, 0xd0, 0xc0, 0x00, + 0x30, 0x98, 0x4c, 0x25, 0x20, 0x00, + 0xa2, 0x51, 0x22, 0x28, 0x48, 0x00, + 0xd0, 0x03, 0x42, 0x53, 0x00, 0x00, + 0xee, 0xf5, 0xb3, 0x66, 0x10, 0x00 +}; + +const uint8_t kMaskRandom37_4[24] = { + 0xec, 0x76, 0x3b, 0x1c, 0xc0, 0x00, + 0x67, 0x33, 0x99, 0xc6, 0x70, 0x00, + 0xb1, 0xd8, 0xec, 0x73, 0x18, 0x00, + 0x5a, 0xad, 0x56, 0xa5, 0xa8, 0x00 +}; + +const uint8_t kMaskRandom37_5[30] = { + 0x4c, 0xa6, 0x53, 0x39, 0xc0, 0x00, + 0x66, 0x33, 0x19, 0x8c, 0x70, 0x00, + 0x19, 0xd0, 0xe8, 0x73, 0x18, 0x00, + 0x9c, 0x89, 0x64, 0xa9, 0xa8, 0x00, + 0xe3, 0x4c, 0x2e, 0x26, 0x60, 0x00 +}; + +const uint8_t kMaskRandom37_6[36] = { + 0xcc, 0x26, 0x13, 0x0d, 0x80, 0x00, + 0x45, 0x62, 0x91, 0x5a, 0x20, 0x00, + 0xb0, 0x98, 0x4c, 0x34, 0x18, 0x00, + 0x8a, 0x85, 0x62, 0xa0, 0xa8, 0x00, + 0x29, 0x53, 0x09, 0x82, 0xd0, 0x00, + 0xa6, 0x0a, 0xa5, 0x51, 0x40, 0x00 +}; + +const uint8_t kMaskRandom37_7[42] = { + 0x44, 0xa2, 0x71, 0x28, 0xc0, 0x00, + 0x23, 0x11, 0x88, 0xc6, 0x60, 0x00, + 0x91, 0x48, 0xa4, 0x47, 0x08, 0x00, + 0x0a, 0x85, 0x52, 0xa0, 0xa8, 0x00, + 0x34, 0x1a, 0x0d, 0x12, 0x50, 0x00, + 0x0b, 0x06, 0xa2, 0xd2, 0x80, 0x00, + 0xe0, 0x64, 0x32, 0x09, 0x30, 0x00 +}; + +const uint8_t kMaskRandom37_8[48] = { + 0x16, 0x0b, 0x05, 0x84, 0xe0, 0x00, + 0xc2, 0x61, 0x30, 0x91, 0x30, 0x00, + 0x60, 0xb0, 0x58, 0x3a, 0x08, 0x00, + 0x85, 0x42, 0xa1, 0x44, 0x98, 0x00, + 0x4c, 0x26, 0x33, 0x08, 0x50, 0x00, + 0x29, 0x14, 0x8a, 0x58, 0xc0, 0x00, + 0x11, 0x88, 0xc4, 0x66, 0x30, 0x00, + 0xb0, 0x58, 0x2c, 0x03, 0x18, 0x00 +}; + +const uint8_t kMaskRandom37_9[54] = { + 0x44, 0xa2, 0x51, 0x29, 0xc0, 0x00, + 0x66, 0x26, 0x19, 0x9c, 0x20, 0x00, + 0x90, 0x49, 0x44, 0xb0, 0x38, 0x00, + 0x01, 0xa5, 0xb0, 0xc4, 0x28, 0x00, + 0x0e, 0x12, 0xa3, 0x0a, 0x50, 0x00, + 0x13, 0x0b, 0x04, 0x56, 0xc0, 0x00, + 0x20, 0xd0, 0x48, 0x64, 0xd0, 0x00, + 0xc2, 0x51, 0x28, 0x8b, 0x00, 0x00, + 0x29, 0x0c, 0x86, 0x03, 0x38, 0x00 +}; + +const uint8_t kMaskRandom38_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 +}; + +const uint8_t kMaskRandom38_10[60] = { + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0xcc, 0x75, 0x19, 0x8e, 0xa0, 0x00, + 0x2b, 0x19, 0xc5, 0x63, 0x38, 0x00, + 0x32, 0xd2, 0x66, 0x5a, 0x4c, 0x00, + 0x25, 0x8e, 0xa4, 0xb1, 0xd4, 0x00, + 0x50, 0x88, 0xca, 0x11, 0x18, 0x00 +}; + +const uint8_t kMaskRandom38_11[66] = { + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00 +}; + +const uint8_t kMaskRandom38_12[72] = { + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x90, 0xc8, 0x92, 0x19, 0x10, 0x00 +}; + +const uint8_t kMaskRandom38_13[78] = { + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00 +}; + +const uint8_t kMaskRandom38_14[84] = { + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x6e, 0x27, 0x6d, 0xc4, 0xec, 0x00 +}; + +const uint8_t kMaskRandom38_15[90] = { + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00 +}; + +const uint8_t kMaskRandom38_16[96] = { + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x7e, 0x75, 0xef, 0xce, 0xbc, 0x00 +}; + +const uint8_t kMaskRandom38_17[102] = { + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00 +}; + +const uint8_t kMaskRandom38_18[108] = { + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x51, 0x97, 0x2a, 0x32, 0xe4, 0x00 +}; + +const uint8_t kMaskRandom38_19[114] = { + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x4c, 0x26, 0x09, 0x84, 0xc0, 0x00, + 0x66, 0x28, 0x8c, 0xc5, 0x10, 0x00, + 0x91, 0x50, 0x32, 0x2a, 0x04, 0x00, + 0x42, 0x82, 0x68, 0x50, 0x4c, 0x00, + 0xa4, 0x01, 0xd4, 0x80, 0x38, 0x00, + 0x13, 0x43, 0x02, 0x68, 0x60, 0x00, + 0x30, 0x94, 0x86, 0x12, 0x90, 0x00, + 0x88, 0xa1, 0x31, 0x14, 0x24, 0x00, + 0x09, 0x4c, 0x01, 0x29, 0x80, 0x00, + 0xcd, 0x98, 0x59, 0xb3, 0x08, 0x00 +}; + +const uint8_t kMaskRandom38_2[12] = { + 0xce, 0x77, 0x19, 0xce, 0xe0, 0x00, + 0x39, 0xcc, 0xe7, 0x39, 0x9c, 0x00 +}; + +const uint8_t kMaskRandom38_20[120] = { + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0xcc, 0x75, 0x19, 0x8e, 0xa0, 0x00, + 0x2b, 0x19, 0xc5, 0x63, 0x38, 0x00, + 0x32, 0xd2, 0x66, 0x5a, 0x4c, 0x00, + 0x25, 0x8e, 0xa4, 0xb1, 0xd4, 0x00, + 0x50, 0x88, 0xca, 0x11, 0x18, 0x00, + 0x44, 0xa7, 0x08, 0x94, 0xe0, 0x00, + 0x66, 0x70, 0x8c, 0xce, 0x10, 0x00, + 0x12, 0xc0, 0xe2, 0x58, 0x1c, 0x00, + 0xc3, 0x10, 0xb8, 0x62, 0x14, 0x00, + 0x8c, 0x29, 0x51, 0x85, 0x28, 0x00, + 0x11, 0x5b, 0x02, 0x2b, 0x60, 0x00, + 0x21, 0x93, 0x44, 0x32, 0x68, 0x00, + 0xa2, 0x2c, 0x14, 0x45, 0x80, 0x00, + 0x18, 0x0c, 0xe3, 0x01, 0x9c, 0x00, + 0xe6, 0xbc, 0x88, 0xe3, 0x78, 0x00 +}; + +const uint8_t kMaskRandom38_21[126] = { + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0xcc, 0x75, 0x19, 0x8e, 0xa0, 0x00, + 0x2b, 0x19, 0xc5, 0x63, 0x38, 0x00, + 0x32, 0xd2, 0x66, 0x5a, 0x4c, 0x00, + 0x25, 0x8e, 0xa4, 0xb1, 0xd4, 0x00, + 0x50, 0x88, 0xca, 0x11, 0x18, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00 +}; + +const uint8_t kMaskRandom38_22[132] = { + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0xcc, 0x75, 0x19, 0x8e, 0xa0, 0x00, + 0x2b, 0x19, 0xc5, 0x63, 0x38, 0x00, + 0x32, 0xd2, 0x66, 0x5a, 0x4c, 0x00, + 0x25, 0x8e, 0xa4, 0xb1, 0xd4, 0x00, + 0x50, 0x88, 0xca, 0x11, 0x18, 0x00, + 0x0c, 0x3c, 0x48, 0x3d, 0x58, 0x00 +}; + +const uint8_t kMaskRandom38_23[138] = { + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x90, 0xc8, 0x92, 0x19, 0x10, 0x00 +}; + +const uint8_t kMaskRandom38_24[144] = { + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x90, 0xc8, 0x92, 0x19, 0x10, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x93, 0xc8, 0xb3, 0xbe, 0x5c, 0x00 +}; + +const uint8_t kMaskRandom38_25[150] = { + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x90, 0xc8, 0x92, 0x19, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00 +}; + +const uint8_t kMaskRandom38_26[156] = { + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0xe3, 0x11, 0x9c, 0x60, 0x00, + 0x27, 0x11, 0xc4, 0xe2, 0x38, 0x00, + 0x32, 0x8d, 0x26, 0x51, 0xa4, 0x00, + 0x61, 0x92, 0x6c, 0x32, 0x4c, 0x00, + 0x5c, 0x38, 0x8b, 0x87, 0x10, 0x00, + 0x90, 0xc8, 0x92, 0x19, 0x10, 0x00, + 0x4b, 0xab, 0xfc, 0xe6, 0xe8, 0x00 +}; + +const uint8_t kMaskRandom38_27[162] = { + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x6e, 0x27, 0x6d, 0xc4, 0xec, 0x00 +}; + +const uint8_t kMaskRandom38_28[168] = { + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x6e, 0x27, 0x6d, 0xc4, 0xec, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x70, 0x1b, 0x5b, 0x2c, 0x0c, 0x00 +}; + +const uint8_t kMaskRandom38_29[174] = { + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x6e, 0x27, 0x6d, 0xc4, 0xec, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00 +}; + +const uint8_t kMaskRandom38_3[18] = { + 0xcc, 0x67, 0x19, 0x8c, 0xe0, 0x00, + 0x27, 0x2c, 0xc4, 0xe5, 0x98, 0x00, + 0x92, 0xd2, 0x72, 0x5a, 0x4c, 0x00 +}; + +const uint8_t kMaskRandom38_30[180] = { + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x84, 0x87, 0x10, 0x90, 0xe0, 0x00, + 0x27, 0x19, 0x84, 0xe3, 0x30, 0x00, + 0x51, 0x88, 0x6a, 0x31, 0x0c, 0x00, + 0x1a, 0x22, 0xa3, 0x44, 0x54, 0x00, + 0x68, 0x44, 0x4d, 0x08, 0x88, 0x00, + 0x89, 0x70, 0x11, 0x2e, 0x00, 0x00, + 0x6e, 0x27, 0x6d, 0xc4, 0xec, 0x00, + 0x5b, 0x16, 0xdf, 0xb8, 0xd0, 0x00 +}; + +const uint8_t kMaskRandom38_31[186] = { + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x7e, 0x75, 0xef, 0xce, 0xbc, 0x00 +}; + +const uint8_t kMaskRandom38_32[192] = { + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x7e, 0x75, 0xef, 0xce, 0xbc, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x33, 0x10, 0x02, 0x4e, 0x54, 0x00 +}; + +const uint8_t kMaskRandom38_33[198] = { + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x7e, 0x75, 0xef, 0xce, 0xbc, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00 +}; + +const uint8_t kMaskRandom38_34[204] = { + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x8c, 0x23, 0x11, 0x84, 0x60, 0x00, + 0x47, 0x19, 0x88, 0xe3, 0x30, 0x00, + 0x81, 0x88, 0x70, 0x31, 0x0c, 0x00, + 0x12, 0x86, 0x22, 0x50, 0xc4, 0x00, + 0x58, 0x14, 0x4b, 0x02, 0x88, 0x00, + 0x28, 0xca, 0x05, 0x19, 0x40, 0x00, + 0x34, 0x60, 0x86, 0x8c, 0x10, 0x00, + 0x7e, 0x75, 0xef, 0xce, 0xbc, 0x00, + 0x91, 0x48, 0xfa, 0xf0, 0xd8, 0x00 +}; + +const uint8_t kMaskRandom38_35[210] = { + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x51, 0x97, 0x2a, 0x32, 0xe4, 0x00 +}; + +const uint8_t kMaskRandom38_36[216] = { + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x51, 0x97, 0x2a, 0x32, 0xe4, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x80, 0x95, 0xc2, 0x68, 0x28, 0x00 +}; + +const uint8_t kMaskRandom38_37[222] = { + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x51, 0x97, 0x2a, 0x32, 0xe4, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x4c, 0x26, 0x09, 0x84, 0xc0, 0x00, + 0x66, 0x28, 0x8c, 0xc5, 0x10, 0x00, + 0x91, 0x50, 0x32, 0x2a, 0x04, 0x00, + 0x42, 0x82, 0x68, 0x50, 0x4c, 0x00, + 0xa4, 0x01, 0xd4, 0x80, 0x38, 0x00, + 0x13, 0x43, 0x02, 0x68, 0x60, 0x00, + 0x30, 0x94, 0x86, 0x12, 0x90, 0x00, + 0x88, 0xa1, 0x31, 0x14, 0x24, 0x00, + 0x09, 0x4c, 0x01, 0x29, 0x80, 0x00, + 0xcd, 0x98, 0x59, 0xb3, 0x08, 0x00 +}; + +const uint8_t kMaskRandom38_38[228] = { + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x4c, 0x26, 0x09, 0x84, 0xc0, 0x00, + 0x66, 0x28, 0x8c, 0xc5, 0x10, 0x00, + 0x91, 0x50, 0x32, 0x2a, 0x04, 0x00, + 0x42, 0x82, 0x68, 0x50, 0x4c, 0x00, + 0xa4, 0x01, 0xd4, 0x80, 0x38, 0x00, + 0x13, 0x43, 0x02, 0x68, 0x60, 0x00, + 0x30, 0x94, 0x86, 0x12, 0x90, 0x00, + 0x88, 0xa1, 0x31, 0x14, 0x24, 0x00, + 0x09, 0x4c, 0x01, 0x29, 0x80, 0x00, + 0xcd, 0x98, 0x59, 0xb3, 0x08, 0x00, + 0x4c, 0x27, 0x09, 0x84, 0xe0, 0x00, + 0x66, 0x71, 0x8c, 0xce, 0x30, 0x00, + 0x91, 0x40, 0xf2, 0x28, 0x1c, 0x00, + 0x42, 0x90, 0xa8, 0x52, 0x14, 0x00, + 0xa4, 0x29, 0x54, 0x85, 0x28, 0x00, + 0x13, 0x5a, 0x02, 0x6b, 0x40, 0x00, + 0x30, 0x93, 0x46, 0x12, 0x68, 0x00, + 0x88, 0xac, 0x31, 0x15, 0x84, 0x00, + 0x09, 0x0c, 0xc1, 0x21, 0x98, 0x00, + 0x2c, 0x16, 0x05, 0x82, 0xc0, 0x00, + 0x91, 0x40, 0xd2, 0x28, 0x18, 0x00, + 0xc0, 0xd0, 0x38, 0x1a, 0x04, 0x00, + 0x06, 0x82, 0xa0, 0xd0, 0x54, 0x00, + 0xc8, 0x0c, 0x59, 0x01, 0x88, 0x00, + 0x45, 0x61, 0x08, 0xac, 0x20, 0x00, + 0x30, 0x91, 0x46, 0x12, 0x28, 0x00, + 0xa2, 0x28, 0x34, 0x45, 0x04, 0x00, + 0x51, 0x97, 0x2a, 0x32, 0xe4, 0x00, + 0x8c, 0xed, 0x11, 0x5f, 0x24, 0x00 +}; + +const uint8_t kMaskRandom38_4[24] = { + 0xec, 0x73, 0x1d, 0x8e, 0x60, 0x00, + 0x67, 0x19, 0xcc, 0xe3, 0x38, 0x00, + 0xb1, 0xcc, 0x76, 0x39, 0x8c, 0x00, + 0x5a, 0x96, 0xab, 0x52, 0xd4, 0x00 +}; + +const uint8_t kMaskRandom38_5[30] = { + 0x4c, 0xe7, 0x09, 0x9c, 0xe0, 0x00, + 0x66, 0x31, 0xcc, 0xc6, 0x38, 0x00, + 0xa1, 0xcc, 0x74, 0x39, 0x8c, 0x00, + 0x92, 0xa6, 0xb2, 0x54, 0xd4, 0x00, + 0xb8, 0x99, 0x97, 0x13, 0x30, 0x00 +}; + +const uint8_t kMaskRandom38_6[36] = { + 0x4c, 0x36, 0x09, 0x86, 0xc0, 0x00, + 0x45, 0x68, 0x88, 0xad, 0x10, 0x00, + 0x30, 0xd0, 0x66, 0x1a, 0x0c, 0x00, + 0x8a, 0x82, 0xb1, 0x50, 0x54, 0x00, + 0x26, 0x0b, 0x44, 0xc1, 0x68, 0x00, + 0x95, 0x45, 0x12, 0xa8, 0xa0, 0x00 +}; + +const uint8_t kMaskRandom38_7[42] = { + 0xc4, 0xa3, 0x18, 0x94, 0x60, 0x00, + 0x23, 0x19, 0x84, 0x63, 0x30, 0x00, + 0x91, 0x1c, 0x32, 0x23, 0x84, 0x00, + 0x4a, 0x82, 0xa9, 0x50, 0x54, 0x00, + 0x34, 0x49, 0x46, 0x89, 0x28, 0x00, + 0x8b, 0x4a, 0x11, 0x69, 0x40, 0x00, + 0xc8, 0x24, 0xd9, 0x04, 0x98, 0x00 +}; + +const uint8_t kMaskRandom38_8[48] = { + 0x16, 0x13, 0x82, 0xc2, 0x70, 0x00, + 0xc2, 0x44, 0xd8, 0x48, 0x98, 0x00, + 0x60, 0xe8, 0x2c, 0x1d, 0x04, 0x00, + 0x85, 0x12, 0x70, 0xa2, 0x4c, 0x00, + 0xcc, 0x21, 0x59, 0x84, 0x28, 0x00, + 0x29, 0x63, 0x05, 0x2c, 0x60, 0x00, + 0x11, 0x98, 0xc2, 0x33, 0x18, 0x00, + 0xb0, 0x0c, 0x76, 0x01, 0x8c, 0x00 +}; + +const uint8_t kMaskRandom38_9[54] = { + 0x44, 0xa7, 0x08, 0x94, 0xe0, 0x00, + 0x66, 0x70, 0x8c, 0xce, 0x10, 0x00, + 0x12, 0xc0, 0xe2, 0x58, 0x1c, 0x00, + 0xc3, 0x10, 0xb8, 0x62, 0x14, 0x00, + 0x8c, 0x29, 0x51, 0x85, 0x28, 0x00, + 0x11, 0x5b, 0x02, 0x2b, 0x60, 0x00, + 0x21, 0x93, 0x44, 0x32, 0x68, 0x00, + 0xa2, 0x2c, 0x14, 0x45, 0x80, 0x00, + 0x18, 0x0c, 0xe3, 0x01, 0x9c, 0x00 +}; + +const uint8_t kMaskRandom39_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 +}; + +const uint8_t kMaskRandom39_10[60] = { + 0x8c, 0xe3, 0x09, 0x82, 0x60, 0x00, + 0x27, 0x11, 0xca, 0x22, 0x88, 0x00, + 0x32, 0x8d, 0x34, 0x0d, 0x02, 0x00, + 0x61, 0x92, 0x60, 0x98, 0x26, 0x00, + 0x5c, 0x38, 0x80, 0x70, 0x1c, 0x00, + 0xcc, 0x75, 0x10, 0xc4, 0x30, 0x00, + 0x2b, 0x19, 0xc5, 0x21, 0x48, 0x00, + 0x32, 0xd2, 0x68, 0x4a, 0x12, 0x00, + 0x25, 0x8e, 0xb3, 0x04, 0xc0, 0x00, + 0x50, 0x88, 0xc6, 0x11, 0x84, 0x00 +}; + +const uint8_t kMaskRandom39_11[66] = { + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00 +}; + +const uint8_t kMaskRandom39_12[72] = { + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x90, 0xc8, 0x9e, 0xbb, 0x88, 0x00 +}; + +const uint8_t kMaskRandom39_13[78] = { + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00 +}; + +const uint8_t kMaskRandom39_14[84] = { + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x6e, 0x27, 0x6a, 0xc7, 0xc4, 0x00 +}; + +const uint8_t kMaskRandom39_15[90] = { + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00 +}; + +const uint8_t kMaskRandom39_16[96] = { + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x7e, 0x75, 0xe5, 0x03, 0x8c, 0x00 +}; + +const uint8_t kMaskRandom39_17[102] = { + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00 +}; + +const uint8_t kMaskRandom39_18[108] = { + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x51, 0x97, 0x24, 0x2f, 0x7e, 0x00 +}; + +const uint8_t kMaskRandom39_19[114] = { + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x4c, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x66, 0x28, 0x8a, 0x22, 0x88, 0x00, + 0x91, 0x50, 0x34, 0x0d, 0x02, 0x00, + 0x42, 0x82, 0x60, 0x98, 0x26, 0x00, + 0xa4, 0x01, 0xc0, 0x70, 0x1c, 0x00, + 0x13, 0x43, 0x10, 0xc4, 0x30, 0x00, + 0x30, 0x94, 0x85, 0x21, 0x48, 0x00, + 0x88, 0xa1, 0x28, 0x4a, 0x12, 0x00, + 0x09, 0x4c, 0x13, 0x04, 0xc0, 0x00, + 0xcd, 0x98, 0x46, 0x11, 0x84, 0x00 +}; + +const uint8_t kMaskRandom39_2[12] = { + 0xce, 0x77, 0x1d, 0xc7, 0x70, 0x00, + 0x39, 0xcc, 0xf3, 0x3c, 0xce, 0x00 +}; + +const uint8_t kMaskRandom39_20[120] = { + 0x8c, 0xe3, 0x09, 0x82, 0x60, 0x00, + 0x27, 0x11, 0xca, 0x22, 0x88, 0x00, + 0x32, 0x8d, 0x34, 0x0d, 0x02, 0x00, + 0x61, 0x92, 0x60, 0x98, 0x26, 0x00, + 0x5c, 0x38, 0x80, 0x70, 0x1c, 0x00, + 0xcc, 0x75, 0x10, 0xc4, 0x30, 0x00, + 0x2b, 0x19, 0xc5, 0x21, 0x48, 0x00, + 0x32, 0xd2, 0x68, 0x4a, 0x12, 0x00, + 0x25, 0x8e, 0xb3, 0x04, 0xc0, 0x00, + 0x50, 0x88, 0xc6, 0x11, 0x84, 0x00, + 0x44, 0xa7, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x70, 0x8c, 0x47, 0x18, 0x00, + 0x12, 0xc0, 0xf0, 0x3c, 0x0e, 0x00, + 0xc3, 0x10, 0xbc, 0x29, 0x0a, 0x00, + 0x8c, 0x29, 0x42, 0x72, 0x94, 0x00, + 0x11, 0x5b, 0x16, 0x85, 0xa0, 0x00, + 0x21, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0xa2, 0x2c, 0x0b, 0x0a, 0xc2, 0x00, + 0x18, 0x0c, 0xe9, 0x30, 0xca, 0x00, + 0x0d, 0xba, 0x52, 0x38, 0xbc, 0x00 +}; + +const uint8_t kMaskRandom39_21[126] = { + 0x8c, 0xe3, 0x09, 0x82, 0x60, 0x00, + 0x27, 0x11, 0xca, 0x22, 0x88, 0x00, + 0x32, 0x8d, 0x34, 0x0d, 0x02, 0x00, + 0x61, 0x92, 0x60, 0x98, 0x26, 0x00, + 0x5c, 0x38, 0x80, 0x70, 0x1c, 0x00, + 0xcc, 0x75, 0x10, 0xc4, 0x30, 0x00, + 0x2b, 0x19, 0xc5, 0x21, 0x48, 0x00, + 0x32, 0xd2, 0x68, 0x4a, 0x12, 0x00, + 0x25, 0x8e, 0xb3, 0x04, 0xc0, 0x00, + 0x50, 0x88, 0xc6, 0x11, 0x84, 0x00, + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00 +}; + +const uint8_t kMaskRandom39_22[132] = { + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0xe3, 0x09, 0x82, 0x60, 0x00, + 0x27, 0x11, 0xca, 0x22, 0x88, 0x00, + 0x32, 0x8d, 0x34, 0x0d, 0x02, 0x00, + 0x61, 0x92, 0x60, 0x98, 0x26, 0x00, + 0x5c, 0x38, 0x80, 0x70, 0x1c, 0x00, + 0xcc, 0x75, 0x10, 0xc4, 0x30, 0x00, + 0x2b, 0x19, 0xc5, 0x21, 0x48, 0x00, + 0x32, 0xd2, 0x68, 0x4a, 0x12, 0x00, + 0x25, 0x8e, 0xb3, 0x04, 0xc0, 0x00, + 0x50, 0x88, 0xc6, 0x11, 0x84, 0x00, + 0xfc, 0x5a, 0xb2, 0x13, 0x12, 0x00 +}; + +const uint8_t kMaskRandom39_23[138] = { + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x90, 0xc8, 0x9e, 0xbb, 0x88, 0x00 +}; + +const uint8_t kMaskRandom39_24[144] = { + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x90, 0xc8, 0x9e, 0xbb, 0x88, 0x00, + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0xac, 0xbc, 0xf0, 0xff, 0x62, 0x00 +}; + +const uint8_t kMaskRandom39_25[150] = { + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x90, 0xc8, 0x9e, 0xbb, 0x88, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00 +}; + +const uint8_t kMaskRandom39_26[156] = { + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0xe3, 0x18, 0xc6, 0x30, 0x00, + 0x27, 0x11, 0xc4, 0x71, 0x1c, 0x00, + 0x32, 0x8d, 0x23, 0x48, 0xd2, 0x00, + 0x61, 0x92, 0x64, 0x99, 0x26, 0x00, + 0x5c, 0x38, 0x8e, 0x23, 0x88, 0x00, + 0x90, 0xc8, 0x9e, 0xbb, 0x88, 0x00, + 0x10, 0x17, 0x44, 0x72, 0xec, 0x00 +}; + +const uint8_t kMaskRandom39_27[162] = { + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x6e, 0x27, 0x6a, 0xc7, 0xc4, 0x00 +}; + +const uint8_t kMaskRandom39_28[168] = { + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x6e, 0x27, 0x6a, 0xc7, 0xc4, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x86, 0xb6, 0x04, 0xbc, 0x1e, 0x00 +}; + +const uint8_t kMaskRandom39_29[174] = { + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x6e, 0x27, 0x6a, 0xc7, 0xc4, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00 +}; + +const uint8_t kMaskRandom39_3[18] = { + 0xcc, 0x67, 0x19, 0xc6, 0x70, 0x00, + 0x27, 0x2c, 0xca, 0xb2, 0xac, 0x00, + 0x92, 0xd2, 0x76, 0x2d, 0x46, 0x00 +}; + +const uint8_t kMaskRandom39_30[180] = { + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x84, 0x87, 0x01, 0xc0, 0x70, 0x00, + 0x27, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x51, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x1a, 0x22, 0xa8, 0xaa, 0x2a, 0x00, + 0x68, 0x44, 0x51, 0x14, 0x44, 0x00, + 0x89, 0x70, 0x1c, 0x07, 0x00, 0x00, + 0x6e, 0x27, 0x6a, 0xc7, 0xc4, 0x00, + 0xb3, 0x1d, 0x13, 0x03, 0x5a, 0x00 +}; + +const uint8_t kMaskRandom39_31[186] = { + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x7e, 0x75, 0xe5, 0x03, 0x8c, 0x00 +}; + +const uint8_t kMaskRandom39_32[192] = { + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x7e, 0x75, 0xe5, 0x03, 0x8c, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x83, 0x1a, 0x3c, 0x2a, 0x7a, 0x00 +}; + +const uint8_t kMaskRandom39_33[198] = { + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x7e, 0x75, 0xe5, 0x03, 0x8c, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00 +}; + +const uint8_t kMaskRandom39_34[204] = { + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x8c, 0x23, 0x08, 0xc2, 0x30, 0x00, + 0x47, 0x19, 0x86, 0x61, 0x98, 0x00, + 0x81, 0x88, 0x62, 0x18, 0x86, 0x00, + 0x12, 0x86, 0x21, 0x88, 0x62, 0x00, + 0x58, 0x14, 0x45, 0x11, 0x44, 0x00, + 0x28, 0xca, 0x12, 0x84, 0xa0, 0x00, + 0x34, 0x60, 0x98, 0x26, 0x08, 0x00, + 0x7e, 0x75, 0xe5, 0x03, 0x8c, 0x00, + 0xc6, 0xbb, 0x7e, 0xd9, 0x80, 0x00 +}; + +const uint8_t kMaskRandom39_35[210] = { + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x51, 0x97, 0x24, 0x2f, 0x7e, 0x00 +}; + +const uint8_t kMaskRandom39_36[216] = { + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x51, 0x97, 0x24, 0x2f, 0x7e, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x11, 0x78, 0xfe, 0x43, 0xd6, 0x00 +}; + +const uint8_t kMaskRandom39_37[222] = { + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x51, 0x97, 0x24, 0x2f, 0x7e, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x4c, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x66, 0x28, 0x8a, 0x22, 0x88, 0x00, + 0x91, 0x50, 0x34, 0x0d, 0x02, 0x00, + 0x42, 0x82, 0x60, 0x98, 0x26, 0x00, + 0xa4, 0x01, 0xc0, 0x70, 0x1c, 0x00, + 0x13, 0x43, 0x10, 0xc4, 0x30, 0x00, + 0x30, 0x94, 0x85, 0x21, 0x48, 0x00, + 0x88, 0xa1, 0x28, 0x4a, 0x12, 0x00, + 0x09, 0x4c, 0x13, 0x04, 0xc0, 0x00, + 0xcd, 0x98, 0x46, 0x11, 0x84, 0x00 +}; + +const uint8_t kMaskRandom39_38[228] = { + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x4c, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x66, 0x28, 0x8a, 0x22, 0x88, 0x00, + 0x91, 0x50, 0x34, 0x0d, 0x02, 0x00, + 0x42, 0x82, 0x60, 0x98, 0x26, 0x00, + 0xa4, 0x01, 0xc0, 0x70, 0x1c, 0x00, + 0x13, 0x43, 0x10, 0xc4, 0x30, 0x00, + 0x30, 0x94, 0x85, 0x21, 0x48, 0x00, + 0x88, 0xa1, 0x28, 0x4a, 0x12, 0x00, + 0x09, 0x4c, 0x13, 0x04, 0xc0, 0x00, + 0xcd, 0x98, 0x46, 0x11, 0x84, 0x00, + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x2c, 0x16, 0x05, 0x81, 0x60, 0x00, + 0x91, 0x40, 0xd0, 0x34, 0x0c, 0x00, + 0xc0, 0xd0, 0x34, 0x0d, 0x02, 0x00, + 0x06, 0x82, 0xa0, 0xa8, 0x2a, 0x00, + 0xc8, 0x0c, 0x43, 0x10, 0xc4, 0x00, + 0x45, 0x61, 0x18, 0x46, 0x10, 0x00, + 0x30, 0x91, 0x44, 0x51, 0x14, 0x00, + 0xa2, 0x28, 0x2a, 0x0a, 0x82, 0x00, + 0x51, 0x97, 0x24, 0x2f, 0x7e, 0x00, + 0x9e, 0xd8, 0x3c, 0x7e, 0x2e, 0x00 +}; + +const uint8_t kMaskRandom39_39[234] = { + 0x4c, 0x27, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x71, 0x9c, 0x67, 0x18, 0x00, + 0x91, 0x40, 0xf0, 0x3c, 0x0e, 0x00, + 0x42, 0x90, 0xa4, 0x29, 0x0a, 0x00, + 0xa4, 0x29, 0x4a, 0x52, 0x94, 0x00, + 0x13, 0x5a, 0x16, 0x85, 0xa0, 0x00, + 0x30, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0x88, 0xac, 0x2b, 0x0a, 0xc2, 0x00, + 0x09, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x4c, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x66, 0x28, 0x8a, 0x22, 0x88, 0x00, + 0x91, 0x50, 0x34, 0x0d, 0x02, 0x00, + 0x42, 0x82, 0x60, 0x98, 0x26, 0x00, + 0xa4, 0x01, 0xc0, 0x70, 0x1c, 0x00, + 0x13, 0x43, 0x10, 0xc4, 0x30, 0x00, + 0x30, 0x94, 0x85, 0x21, 0x48, 0x00, + 0x88, 0xa1, 0x28, 0x4a, 0x12, 0x00, + 0x09, 0x4c, 0x13, 0x04, 0xc0, 0x00, + 0xcd, 0x98, 0x46, 0x11, 0x84, 0x00, + 0x4c, 0x27, 0x09, 0x82, 0x60, 0x00, + 0x66, 0x71, 0x8a, 0x22, 0x88, 0x00, + 0x91, 0x40, 0xf4, 0x0d, 0x02, 0x00, + 0x42, 0x90, 0xa0, 0x98, 0x26, 0x00, + 0xa4, 0x29, 0x40, 0x70, 0x1c, 0x00, + 0x13, 0x5a, 0x10, 0xc4, 0x30, 0x00, + 0x30, 0x93, 0x45, 0x21, 0x48, 0x00, + 0x88, 0xac, 0x28, 0x4a, 0x12, 0x00, + 0x09, 0x0c, 0xd3, 0x04, 0xc0, 0x00, + 0x4c, 0x26, 0x06, 0x11, 0x84, 0x00, + 0x66, 0x28, 0x89, 0xc2, 0x70, 0x00, + 0x91, 0x50, 0x3c, 0x67, 0x18, 0x00, + 0x42, 0x82, 0x70, 0x3c, 0x0e, 0x00, + 0xa4, 0x01, 0xc4, 0x29, 0x0a, 0x00, + 0x13, 0x43, 0x0a, 0x52, 0x94, 0x00, + 0x30, 0x94, 0x96, 0x85, 0xa0, 0x00, + 0x88, 0xa1, 0x24, 0xd1, 0x34, 0x00, + 0x09, 0x4c, 0x0b, 0x0a, 0xc2, 0x00, + 0xcd, 0x98, 0x43, 0x30, 0xcc, 0x00, + 0x1d, 0x04, 0x3e, 0xf1, 0xb4, 0x00 +}; + +const uint8_t kMaskRandom39_4[24] = { + 0xec, 0x73, 0x1c, 0xc7, 0x30, 0x00, + 0x67, 0x19, 0xc6, 0x71, 0x9c, 0x00, + 0xb1, 0xcc, 0x73, 0x1c, 0xc6, 0x00, + 0x5a, 0x96, 0xa5, 0xa9, 0x6a, 0x00 +}; + +const uint8_t kMaskRandom39_5[30] = { + 0x4c, 0xe7, 0x19, 0xc6, 0x70, 0x00, + 0x66, 0x31, 0xcc, 0x73, 0x1c, 0x00, + 0xa1, 0xcc, 0x73, 0x1c, 0xa6, 0x00, + 0x92, 0xa6, 0xa5, 0x6a, 0x6a, 0x00, + 0xb8, 0x99, 0x96, 0x8b, 0x94, 0x00 +}; + +const uint8_t kMaskRandom39_6[36] = { + 0x4c, 0x36, 0x09, 0x83, 0x60, 0x00, + 0x45, 0x68, 0x8a, 0x26, 0x88, 0x00, + 0x30, 0xd0, 0x64, 0x1d, 0x06, 0x00, + 0x8a, 0x82, 0xb0, 0xa8, 0x2a, 0x00, + 0x26, 0x0b, 0x40, 0xd0, 0xd4, 0x00, + 0x95, 0x45, 0x13, 0x44, 0x30, 0x00 +}; + +const uint8_t kMaskRandom39_7[42] = { + 0xc4, 0xa3, 0x09, 0xc2, 0x30, 0x00, + 0x23, 0x19, 0x86, 0x65, 0x80, 0x00, + 0x91, 0x1c, 0x22, 0x01, 0xd6, 0x00, + 0x4a, 0x82, 0xb0, 0x2a, 0x2a, 0x00, + 0x34, 0x49, 0x44, 0x98, 0x94, 0x00, + 0x8b, 0x4a, 0x1a, 0x84, 0x60, 0x00, + 0xc8, 0x24, 0xc1, 0x94, 0x4c, 0x00 +}; + +const uint8_t kMaskRandom39_8[48] = { + 0x16, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xc2, 0x44, 0xd1, 0x34, 0x4c, 0x00, + 0x60, 0xe8, 0x3a, 0x0e, 0x82, 0x00, + 0x85, 0x12, 0x64, 0x99, 0x26, 0x00, + 0xcc, 0x21, 0x5c, 0x52, 0x14, 0x00, + 0x29, 0x63, 0x18, 0xc6, 0x30, 0x00, + 0x11, 0x98, 0xc6, 0x31, 0x8c, 0x00, + 0xb0, 0x0c, 0x63, 0x18, 0xc6, 0x00 +}; + +const uint8_t kMaskRandom39_9[54] = { + 0x44, 0xa7, 0x09, 0xc2, 0x70, 0x00, + 0x66, 0x70, 0x8c, 0x47, 0x18, 0x00, + 0x12, 0xc0, 0xf0, 0x3c, 0x0e, 0x00, + 0xc3, 0x10, 0xbc, 0x29, 0x0a, 0x00, + 0x8c, 0x29, 0x42, 0x72, 0x94, 0x00, + 0x11, 0x5b, 0x16, 0x85, 0xa0, 0x00, + 0x21, 0x93, 0x44, 0xd1, 0x34, 0x00, + 0xa2, 0x2c, 0x0b, 0x0a, 0xc2, 0x00, + 0x18, 0x0c, 0xe9, 0x30, 0xca, 0x00 +}; + +const uint8_t kMaskRandom3_1[2] = { + 0xe0, 0x00 +}; + +const uint8_t kMaskRandom3_2[4] = { + 0xc0, 0x00, + 0xa0, 0x00 +}; + +const uint8_t kMaskRandom3_3[6] = { + 0xc0, 0x00, + 0xa0, 0x00, + 0x60, 0x00 +}; + +const uint8_t kMaskRandom40_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 +}; + +const uint8_t kMaskRandom40_10[60] = { + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00 +}; + +const uint8_t kMaskRandom40_11[66] = { + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00 +}; + +const uint8_t kMaskRandom40_12[72] = { + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0xf5, 0xdc, 0x4f, 0x5d, 0xc4, 0x00 +}; + +const uint8_t kMaskRandom40_13[78] = { + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00 +}; + +const uint8_t kMaskRandom40_14[84] = { + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x56, 0x3e, 0x25, 0x63, 0xe2, 0x00 +}; + +const uint8_t kMaskRandom40_15[90] = { + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00 +}; + +const uint8_t kMaskRandom40_16[96] = { + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x28, 0x1c, 0x62, 0x81, 0xc6, 0x00 +}; + +const uint8_t kMaskRandom40_17[102] = { + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00 +}; + +const uint8_t kMaskRandom40_18[108] = { + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x21, 0x7b, 0xf2, 0x17, 0xbf, 0x00 +}; + +const uint8_t kMaskRandom40_19[114] = { + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00 +}; + +const uint8_t kMaskRandom40_2[12] = { + 0xee, 0x3b, 0x8e, 0xe3, 0xb8, 0x00, + 0x99, 0xe6, 0x79, 0x9e, 0x67, 0x00 +}; + +const uint8_t kMaskRandom40_20[120] = { + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0xf7, 0x8d, 0xaf, 0x78, 0xda, 0x00 +}; + +const uint8_t kMaskRandom40_21[126] = { + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00 +}; + +const uint8_t kMaskRandom40_22[132] = { + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0x89, 0xee, 0x1f, 0x38, 0xca, 0x00 +}; + +const uint8_t kMaskRandom40_23[138] = { + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0xf5, 0xdc, 0x4f, 0x5d, 0xc4, 0x00 +}; + +const uint8_t kMaskRandom40_24[144] = { + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0xf5, 0xdc, 0x4f, 0x5d, 0xc4, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x68, 0xde, 0x83, 0xa9, 0xcf, 0x00 +}; + +const uint8_t kMaskRandom40_25[150] = { + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0xf5, 0xdc, 0x4f, 0x5d, 0xc4, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00 +}; + +const uint8_t kMaskRandom40_26[156] = { + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8e, 0x00, + 0x1a, 0x46, 0x91, 0xa4, 0x69, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0x71, 0x1c, 0x47, 0x11, 0xc4, 0x00, + 0xf5, 0xdc, 0x4f, 0x5d, 0xc4, 0x00, + 0x06, 0x8e, 0x8c, 0x1a, 0xd2, 0x00 +}; + +const uint8_t kMaskRandom40_27[162] = { + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x56, 0x3e, 0x25, 0x63, 0xe2, 0x00 +}; + +const uint8_t kMaskRandom40_28[168] = { + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x56, 0x3e, 0x25, 0x63, 0xe2, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x68, 0x0e, 0x9b, 0x52, 0xb6, 0x00 +}; + +const uint8_t kMaskRandom40_29[174] = { + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x56, 0x3e, 0x25, 0x63, 0xe2, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00 +}; + +const uint8_t kMaskRandom40_3[18] = { + 0xce, 0x33, 0x8c, 0xe3, 0x38, 0x00, + 0x55, 0x95, 0x65, 0x59, 0x56, 0x00, + 0xb1, 0x6a, 0x3b, 0x16, 0xa3, 0x00 +}; + +const uint8_t kMaskRandom40_30[180] = { + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x0e, 0x03, 0x80, 0xe0, 0x38, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x45, 0x51, 0x54, 0x55, 0x15, 0x00, + 0x88, 0xa2, 0x28, 0x8a, 0x22, 0x00, + 0xe0, 0x38, 0x0e, 0x03, 0x80, 0x00, + 0x56, 0x3e, 0x25, 0x63, 0xe2, 0x00, + 0xe1, 0x47, 0x04, 0x05, 0x47, 0x00 +}; + +const uint8_t kMaskRandom40_31[186] = { + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x28, 0x1c, 0x62, 0x81, 0xc6, 0x00 +}; + +const uint8_t kMaskRandom40_32[192] = { + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x28, 0x1c, 0x62, 0x81, 0xc6, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x03, 0x0c, 0x46, 0x10, 0xc5, 0x00 +}; + +const uint8_t kMaskRandom40_33[198] = { + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x28, 0x1c, 0x62, 0x81, 0xc6, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00 +}; + +const uint8_t kMaskRandom40_34[204] = { + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x18, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x43, 0x00, + 0x0c, 0x43, 0x10, 0xc4, 0x31, 0x00, + 0x28, 0x8a, 0x22, 0x88, 0xa2, 0x00, + 0x94, 0x25, 0x09, 0x42, 0x50, 0x00, + 0xc1, 0x30, 0x4c, 0x13, 0x04, 0x00, + 0x28, 0x1c, 0x62, 0x81, 0xc6, 0x00, + 0x87, 0x3c, 0x08, 0x19, 0x31, 0x00 +}; + +const uint8_t kMaskRandom40_35[210] = { + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x21, 0x7b, 0xf2, 0x17, 0xbf, 0x00 +}; + +const uint8_t kMaskRandom40_36[216] = { + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x21, 0x7b, 0xf2, 0x17, 0xbf, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x1e, 0xb9, 0x3d, 0x25, 0xcc, 0x00 +}; + +const uint8_t kMaskRandom40_37[222] = { + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x21, 0x7b, 0xf2, 0x17, 0xbf, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00 +}; + +const uint8_t kMaskRandom40_38[228] = { + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0xb0, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x06, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x88, 0x62, 0x00, + 0xc2, 0x30, 0x8c, 0x23, 0x08, 0x00, + 0x22, 0x88, 0xa2, 0x28, 0x8a, 0x00, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x00, + 0x21, 0x7b, 0xf2, 0x17, 0xbf, 0x00, + 0xea, 0xaa, 0x20, 0xa2, 0x1b, 0x00 +}; + +const uint8_t kMaskRandom40_39[234] = { + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0xf7, 0x8d, 0xaf, 0x78, 0xda, 0x00 +}; + +const uint8_t kMaskRandom40_4[24] = { + 0xe6, 0x39, 0x8e, 0x63, 0x98, 0x00, + 0x33, 0x8c, 0xe3, 0x38, 0xce, 0x00, + 0x98, 0xe6, 0x39, 0x8e, 0x63, 0x00, + 0x2d, 0x4b, 0x52, 0xd4, 0xb5, 0x00 +}; + +const uint8_t kMaskRandom40_40[240] = { + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0xf7, 0x8d, 0xaf, 0x78, 0xda, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0xe3, 0x38, 0xce, 0x33, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x85, 0x00, + 0x52, 0x94, 0xa5, 0x29, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x19, 0x86, 0x61, 0x98, 0x66, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x30, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x44, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0x81, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x38, 0x0e, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x18, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0xa4, 0x00, + 0x42, 0x50, 0x94, 0x25, 0x09, 0x00, + 0x98, 0x26, 0x09, 0x82, 0x60, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0xc2, 0x00, + 0xa6, 0xf3, 0xab, 0x1b, 0x87, 0x00 +}; + +const uint8_t kMaskRandom40_5[30] = { + 0xce, 0x33, 0x8c, 0xe3, 0x38, 0x00, + 0x63, 0x98, 0xe6, 0x39, 0x8e, 0x00, + 0x98, 0xe5, 0x39, 0x8e, 0x53, 0x00, + 0x2b, 0x53, 0x52, 0xb5, 0x35, 0x00, + 0xb4, 0x5c, 0xab, 0x45, 0xca, 0x00 +}; + +const uint8_t kMaskRandom40_6[36] = { + 0x4c, 0x1b, 0x04, 0xc1, 0xb0, 0x00, + 0x51, 0x34, 0x45, 0x13, 0x44, 0x00, + 0x20, 0xe8, 0x32, 0x0e, 0x83, 0x00, + 0x85, 0x41, 0x58, 0x54, 0x15, 0x00, + 0x06, 0x86, 0xa0, 0x68, 0x6a, 0x00, + 0x9a, 0x21, 0x89, 0xa2, 0x18, 0x00 +}; + +const uint8_t kMaskRandom40_7[42] = { + 0x4e, 0x11, 0x84, 0xe1, 0x18, 0x00, + 0x33, 0x2c, 0x03, 0x32, 0xc0, 0x00, + 0x10, 0x0e, 0xb1, 0x00, 0xeb, 0x00, + 0x81, 0x51, 0x58, 0x15, 0x15, 0x00, + 0x24, 0xc4, 0xa2, 0x4c, 0x4a, 0x00, + 0xd4, 0x23, 0x0d, 0x42, 0x30, 0x00, + 0x0c, 0xa2, 0x60, 0xca, 0x26, 0x00 +}; + +const uint8_t kMaskRandom40_8[48] = { + 0x27, 0x09, 0xc2, 0x70, 0x9c, 0x00, + 0x89, 0xa2, 0x68, 0x9a, 0x26, 0x00, + 0xd0, 0x74, 0x1d, 0x07, 0x41, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x93, 0x00, + 0xe2, 0x90, 0xae, 0x29, 0x0a, 0x00, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x00, + 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x00 +}; + +const uint8_t kMaskRandom40_9[54] = { + 0x4e, 0x13, 0x84, 0xe1, 0x38, 0x00, + 0x62, 0x38, 0xc6, 0x23, 0x8c, 0x00, + 0x81, 0xe0, 0x78, 0x1e, 0x07, 0x00, + 0xe1, 0x48, 0x5e, 0x14, 0x85, 0x00, + 0x13, 0x94, 0xa1, 0x39, 0x4a, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0xd0, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x9a, 0x00, + 0x58, 0x56, 0x15, 0x85, 0x61, 0x00, + 0x49, 0x86, 0x54, 0x98, 0x65, 0x00 +}; + +const uint8_t kMaskRandom41_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 +}; + +const uint8_t kMaskRandom41_10[60] = { + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80 +}; + +const uint8_t kMaskRandom41_11[66] = { + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00 +}; + +const uint8_t kMaskRandom41_12[72] = { + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0xf5, 0xdc, 0x4a, 0x06, 0x51, 0x80 +}; + +const uint8_t kMaskRandom41_13[78] = { + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80 +}; + +const uint8_t kMaskRandom41_14[84] = { + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x56, 0x3e, 0x24, 0xdd, 0x0c, 0x00 +}; + +const uint8_t kMaskRandom41_15[90] = { + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80 +}; + +const uint8_t kMaskRandom41_16[96] = { + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x28, 0x1c, 0x63, 0xbf, 0x53, 0x80 +}; + +const uint8_t kMaskRandom41_17[102] = { + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom41_18[108] = { + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x21, 0x7b, 0xf5, 0xa5, 0x65, 0x80 +}; + +const uint8_t kMaskRandom41_19[114] = { + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80 +}; + +const uint8_t kMaskRandom41_2[12] = { + 0xee, 0x3b, 0x8e, 0xe3, 0xb3, 0x00, + 0x99, 0xe6, 0x79, 0x9e, 0x6e, 0x80 +}; + +const uint8_t kMaskRandom41_20[120] = { + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0xf7, 0x8d, 0xa2, 0xa0, 0x33, 0x00 +}; + +const uint8_t kMaskRandom41_21[126] = { + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00 +}; + +const uint8_t kMaskRandom41_22[132] = { + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x33, 0x09, 0x6e, 0x49, 0x6b, 0x80 +}; + +const uint8_t kMaskRandom41_23[138] = { + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0xf5, 0xdc, 0x4a, 0x06, 0x51, 0x80 +}; + +const uint8_t kMaskRandom41_24[144] = { + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0xf5, 0xdc, 0x4a, 0x06, 0x51, 0x80, + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x45, 0xa6, 0xef, 0xc9, 0xc3, 0x00 +}; + +const uint8_t kMaskRandom41_25[150] = { + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0xf5, 0xdc, 0x4a, 0x06, 0x51, 0x80, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80 +}; + +const uint8_t kMaskRandom41_26[156] = { + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0xc6, 0x31, 0x8c, 0x62, 0x1a, 0x00, + 0x23, 0x88, 0xe2, 0x38, 0x8c, 0x80, + 0x1a, 0x46, 0x91, 0xa4, 0x58, 0x80, + 0x24, 0xc9, 0x32, 0x4d, 0x30, 0x80, + 0x71, 0x1c, 0x47, 0x11, 0x07, 0x00, + 0xf5, 0xdc, 0x4a, 0x06, 0x51, 0x80, + 0x6f, 0x72, 0xf1, 0xe7, 0x1a, 0x80 +}; + +const uint8_t kMaskRandom41_27[162] = { + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x56, 0x3e, 0x24, 0xdd, 0x0c, 0x00 +}; + +const uint8_t kMaskRandom41_28[168] = { + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x56, 0x3e, 0x24, 0xdd, 0x0c, 0x00, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x61, 0x2c, 0xfa, 0x25, 0x38, 0x00 +}; + +const uint8_t kMaskRandom41_29[174] = { + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x56, 0x3e, 0x24, 0xdd, 0x0c, 0x00, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80 +}; + +const uint8_t kMaskRandom41_3[18] = { + 0xce, 0x33, 0x8c, 0xe3, 0x2b, 0x00, + 0x55, 0x95, 0x65, 0x5d, 0xc5, 0x00, + 0xb1, 0x6a, 0x3a, 0x8e, 0xd8, 0x80 +}; + +const uint8_t kMaskRandom41_30[180] = { + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x0e, 0x03, 0x80, 0xe1, 0x91, 0x00, + 0x33, 0x0c, 0xc3, 0x31, 0x45, 0x00, + 0x10, 0xc4, 0x31, 0x0c, 0x32, 0x80, + 0x45, 0x51, 0x54, 0x56, 0x84, 0x80, + 0x88, 0xa2, 0x28, 0x88, 0x4a, 0x80, + 0xe0, 0x38, 0x0e, 0x02, 0x29, 0x00, + 0x56, 0x3e, 0x24, 0xdd, 0x0c, 0x00, + 0x59, 0x53, 0x31, 0x62, 0x15, 0x00 +}; + +const uint8_t kMaskRandom41_31[186] = { + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x28, 0x1c, 0x63, 0xbf, 0x53, 0x80 +}; + +const uint8_t kMaskRandom41_32[192] = { + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x28, 0x1c, 0x63, 0xbf, 0x53, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0xca, 0xbb, 0xcb, 0x6d, 0xaa, 0x00 +}; + +const uint8_t kMaskRandom41_33[198] = { + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x28, 0x1c, 0x63, 0xbf, 0x53, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00 +}; + +const uint8_t kMaskRandom41_34[204] = { + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x46, 0x11, 0x84, 0x61, 0x19, 0x00, + 0x33, 0x0c, 0xc3, 0x30, 0xcc, 0x80, + 0x10, 0xc4, 0x31, 0x0e, 0x46, 0x00, + 0x0c, 0x43, 0x10, 0xc6, 0x90, 0x80, + 0x28, 0x8a, 0x22, 0x89, 0x42, 0x80, + 0x94, 0x25, 0x09, 0x42, 0x13, 0x00, + 0xc1, 0x30, 0x4c, 0x10, 0x25, 0x80, + 0x28, 0x1c, 0x63, 0xbf, 0x53, 0x80, + 0xbd, 0x37, 0x3f, 0x75, 0x36, 0x80 +}; + +const uint8_t kMaskRandom41_35[210] = { + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x21, 0x7b, 0xf5, 0xa5, 0x65, 0x80 +}; + +const uint8_t kMaskRandom41_36[216] = { + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x21, 0x7b, 0xf5, 0xa5, 0x65, 0x80, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0xc1, 0xb1, 0x80, 0xbe, 0x3e, 0x00 +}; + +const uint8_t kMaskRandom41_37[222] = { + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x21, 0x7b, 0xf5, 0xa5, 0x65, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80 +}; + +const uint8_t kMaskRandom41_38[228] = { + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x2c, 0x0b, 0x02, 0xc0, 0x32, 0x00, + 0x81, 0xa0, 0x68, 0x1a, 0x01, 0x80, + 0xa0, 0x68, 0x1a, 0x06, 0x82, 0x00, + 0x05, 0x41, 0x50, 0x54, 0x15, 0x00, + 0x18, 0x86, 0x21, 0x89, 0x0c, 0x00, + 0xc2, 0x30, 0x8c, 0x20, 0x68, 0x00, + 0x22, 0x88, 0xa2, 0x29, 0x80, 0x80, + 0x50, 0x54, 0x15, 0x04, 0x50, 0x80, + 0x21, 0x7b, 0xf5, 0xa5, 0x65, 0x80, + 0xea, 0xc8, 0xbb, 0xd4, 0x5d, 0x00 +}; + +const uint8_t kMaskRandom41_39[234] = { + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0xf7, 0x8d, 0xa2, 0xa0, 0x33, 0x00 +}; + +const uint8_t kMaskRandom41_4[24] = { + 0xe6, 0x39, 0x8e, 0x63, 0x13, 0x00, + 0x33, 0x8c, 0xe3, 0x38, 0xc5, 0x80, + 0x98, 0xe6, 0x39, 0x8d, 0x2c, 0x80, + 0x2d, 0x4b, 0x52, 0xd4, 0xb2, 0x80 +}; + +const uint8_t kMaskRandom41_40[240] = { + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0xf7, 0x8d, 0xa2, 0xa0, 0x33, 0x00, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0xe8, 0x07, 0x18, 0x9a, 0x02, 0x00 +}; + +const uint8_t kMaskRandom41_41[246] = { + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x4e, 0x13, 0x84, 0xe1, 0x19, 0x00, + 0xe3, 0x38, 0xce, 0x31, 0x89, 0x80, + 0x81, 0xe0, 0x78, 0x1e, 0x30, 0x00, + 0x21, 0x48, 0x52, 0x14, 0x05, 0x80, + 0x52, 0x94, 0xa5, 0x28, 0x1e, 0x00, + 0xb4, 0x2d, 0x0b, 0x42, 0x82, 0x00, + 0x26, 0x89, 0xa2, 0x68, 0x62, 0x80, + 0x58, 0x56, 0x15, 0x86, 0x44, 0x00, + 0x19, 0x86, 0x61, 0x99, 0xe0, 0x00, + 0xf7, 0x8d, 0xa2, 0xa0, 0x33, 0x00, + 0x4c, 0x13, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x14, 0x45, 0x11, 0x45, 0x00, + 0xa0, 0x68, 0x1a, 0x06, 0xa4, 0x00, + 0x04, 0xc1, 0x30, 0x4c, 0x13, 0x00, + 0x03, 0x80, 0xe0, 0x3b, 0x40, 0x00, + 0x86, 0x21, 0x88, 0x62, 0x09, 0x00, + 0x29, 0x0a, 0x42, 0x90, 0x84, 0x80, + 0x42, 0x50, 0x94, 0x24, 0x30, 0x80, + 0x98, 0x26, 0x09, 0x81, 0x28, 0x00, + 0x30, 0x8c, 0x23, 0x08, 0x4a, 0x80, + 0x4e, 0x13, 0x84, 0xc1, 0x19, 0x00, + 0xe3, 0x38, 0xc5, 0x10, 0xcc, 0x80, + 0x81, 0xe0, 0x7a, 0x06, 0x64, 0x00, + 0x21, 0x48, 0x50, 0x4c, 0x16, 0x00, + 0x52, 0x94, 0xa0, 0x3a, 0x02, 0x80, + 0xb4, 0x2d, 0x08, 0x62, 0x11, 0x00, + 0x26, 0x89, 0xa2, 0x91, 0x01, 0x80, + 0x58, 0x56, 0x14, 0x24, 0x2a, 0x00, + 0x19, 0x86, 0x69, 0x81, 0xa0, 0x00, + 0xf7, 0x8d, 0xa3, 0x08, 0x40, 0x80, + 0x2b, 0xea, 0x4d, 0xf4, 0xc1, 0x00 +}; + +const uint8_t kMaskRandom41_5[30] = { + 0xce, 0x33, 0x8c, 0xe3, 0x1b, 0x00, + 0x63, 0x98, 0xe6, 0x39, 0x8d, 0x80, + 0x98, 0xe5, 0x39, 0x8c, 0x76, 0x80, + 0x2b, 0x53, 0x54, 0xd6, 0xb5, 0x00, + 0xb4, 0x5c, 0xab, 0x26, 0xca, 0x80 +}; + +const uint8_t kMaskRandom41_6[36] = { + 0x4c, 0x1b, 0x04, 0xc1, 0x91, 0x00, + 0x51, 0x34, 0x45, 0x11, 0x45, 0x00, + 0x20, 0xe8, 0x32, 0x0e, 0xa0, 0x80, + 0x85, 0x41, 0x58, 0x54, 0x12, 0x80, + 0x06, 0x86, 0xa0, 0x68, 0x0d, 0x80, + 0x9a, 0x21, 0x88, 0xa2, 0x43, 0x00 +}; + +const uint8_t kMaskRandom41_7[42] = { + 0x4e, 0x11, 0x8c, 0x61, 0x19, 0x00, + 0x33, 0x2c, 0x03, 0x30, 0x4c, 0x80, + 0x10, 0x0e, 0xb1, 0x86, 0x74, 0x00, + 0x81, 0x51, 0x54, 0x54, 0x2d, 0x00, + 0x24, 0xc4, 0xa1, 0x2d, 0x42, 0x80, + 0xd4, 0x23, 0x0b, 0x42, 0x83, 0x00, + 0x0c, 0xa2, 0x62, 0x99, 0x21, 0x80 +}; + +const uint8_t kMaskRandom41_8[48] = { + 0x27, 0x09, 0xc0, 0x70, 0xa7, 0x00, + 0x89, 0xa2, 0x64, 0x9a, 0x82, 0x80, + 0xd0, 0x74, 0x1b, 0x07, 0xa0, 0x00, + 0x24, 0xc9, 0x32, 0x4c, 0x5c, 0x00, + 0xe2, 0x90, 0xa5, 0x28, 0x0e, 0x80, + 0xc6, 0x31, 0x8c, 0x63, 0x18, 0x00, + 0x31, 0x8c, 0x63, 0x19, 0x41, 0x80, + 0x18, 0xc6, 0x31, 0x8c, 0x70, 0x80 +}; + +const uint8_t kMaskRandom41_9[54] = { + 0x4e, 0x13, 0x84, 0xe1, 0x11, 0x00, + 0x62, 0x38, 0xc6, 0x21, 0xa0, 0x80, + 0x81, 0xe0, 0x78, 0x0e, 0x94, 0x00, + 0xe1, 0x48, 0x5a, 0x15, 0x05, 0x00, + 0x13, 0x94, 0xa5, 0x30, 0x06, 0x80, + 0xb4, 0x2d, 0x0a, 0x42, 0x43, 0x00, + 0x26, 0x89, 0xa1, 0x6a, 0x08, 0x80, + 0x58, 0x56, 0x15, 0x84, 0x52, 0x00, + 0x49, 0x86, 0x52, 0x98, 0x68, 0x00 +}; + +const uint8_t kMaskRandom42_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const uint8_t kMaskRandom42_10[60] = { + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40 +}; + +const uint8_t kMaskRandom42_11[66] = { + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80 +}; + +const uint8_t kMaskRandom42_12[72] = { + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0xa0, 0x65, 0x1d, 0x03, 0x28, 0xc0 +}; + +const uint8_t kMaskRandom42_13[78] = { + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0 +}; + +const uint8_t kMaskRandom42_14[84] = { + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x4d, 0xd0, 0xc2, 0x6e, 0x86, 0x00 +}; + +const uint8_t kMaskRandom42_15[90] = { + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40 +}; + +const uint8_t kMaskRandom42_16[96] = { + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x3b, 0xf5, 0x39, 0xdf, 0xa9, 0xc0 +}; + +const uint8_t kMaskRandom42_17[102] = { + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00 +}; + +const uint8_t kMaskRandom42_18[108] = { + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x5a, 0x56, 0x5a, 0xd2, 0xb2, 0xc0 +}; + +const uint8_t kMaskRandom42_19[114] = { + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40 +}; + +const uint8_t kMaskRandom42_2[12] = { + 0xee, 0x3b, 0x37, 0x71, 0xd9, 0x80, + 0x99, 0xe6, 0xec, 0xcf, 0x37, 0x40 +}; + +const uint8_t kMaskRandom42_20[120] = { + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2a, 0x03, 0x31, 0x50, 0x19, 0x80 +}; + +const uint8_t kMaskRandom42_21[126] = { + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4c, 0x11, 0x92, 0x60, 0x8c, 0x80, + 0x51, 0x0c, 0xca, 0x88, 0x66, 0x40, + 0xa0, 0x66, 0x45, 0x03, 0x32, 0x00, + 0x04, 0xc1, 0x60, 0x26, 0x0b, 0x00, + 0x03, 0xa0, 0x28, 0x1d, 0x01, 0x40, + 0x86, 0x21, 0x14, 0x31, 0x08, 0x80, + 0x29, 0x10, 0x19, 0x48, 0x80, 0xc0, + 0x42, 0x42, 0xa2, 0x12, 0x15, 0x00, + 0x98, 0x1a, 0x04, 0xc0, 0xd0, 0x00, + 0x30, 0x84, 0x09, 0x84, 0x20, 0x40, + 0xdf, 0x4c, 0x16, 0xfa, 0x60, 0x80 +}; + +const uint8_t kMaskRandom42_22[132] = { + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0xdb, 0x36, 0xb0, 0x33, 0x14, 0x80 +}; + +const uint8_t kMaskRandom42_23[138] = { + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0xa0, 0x65, 0x1d, 0x03, 0x28, 0xc0 +}; + +const uint8_t kMaskRandom42_24[144] = { + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0xa0, 0x65, 0x1d, 0x03, 0x28, 0xc0, + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x2e, 0x1c, 0x92, 0xbb, 0x07, 0xc0 +}; + +const uint8_t kMaskRandom42_25[150] = { + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0xa0, 0x65, 0x1d, 0x03, 0x28, 0xc0, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0 +}; + +const uint8_t kMaskRandom42_26[156] = { + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0xc6, 0x21, 0xa6, 0x31, 0x0d, 0x00, + 0x23, 0x88, 0xc9, 0x1c, 0x46, 0x40, + 0x1a, 0x45, 0x88, 0xd2, 0x2c, 0x40, + 0x24, 0xd3, 0x09, 0x26, 0x98, 0x40, + 0x71, 0x10, 0x73, 0x88, 0x83, 0x80, + 0xa0, 0x65, 0x1d, 0x03, 0x28, 0xc0, + 0xb8, 0x41, 0xed, 0xa3, 0x77, 0xc0 +}; + +const uint8_t kMaskRandom42_27[162] = { + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x4d, 0xd0, 0xc2, 0x6e, 0x86, 0x00 +}; + +const uint8_t kMaskRandom42_28[168] = { + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x4d, 0xd0, 0xc2, 0x6e, 0x86, 0x00, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0xc3, 0x3c, 0x56, 0xc2, 0x30, 0x40 +}; + +const uint8_t kMaskRandom42_29[174] = { + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x4d, 0xd0, 0xc2, 0x6e, 0x86, 0x00, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40 +}; + +const uint8_t kMaskRandom42_3[18] = { + 0xce, 0x32, 0xb6, 0x71, 0x95, 0x80, + 0x55, 0xdc, 0x52, 0xae, 0xe2, 0x80, + 0xa8, 0xed, 0x8d, 0x47, 0x6c, 0x40 +}; + +const uint8_t kMaskRandom42_30[180] = { + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x0e, 0x19, 0x10, 0x70, 0xc8, 0x80, + 0x33, 0x14, 0x51, 0x98, 0xa2, 0x80, + 0x10, 0xc3, 0x28, 0x86, 0x19, 0x40, + 0x45, 0x68, 0x4a, 0x2b, 0x42, 0x40, + 0x88, 0x84, 0xac, 0x44, 0x25, 0x40, + 0xe0, 0x22, 0x97, 0x01, 0x14, 0x80, + 0x4d, 0xd0, 0xc2, 0x6e, 0x86, 0x00, + 0xf5, 0xdd, 0x0d, 0x58, 0xeb, 0x00 +}; + +const uint8_t kMaskRandom42_31[186] = { + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x3b, 0xf5, 0x39, 0xdf, 0xa9, 0xc0 +}; + +const uint8_t kMaskRandom42_32[192] = { + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x3b, 0xf5, 0x39, 0xdf, 0xa9, 0xc0, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0xf9, 0x1f, 0xb6, 0xe1, 0x09, 0xc0 +}; + +const uint8_t kMaskRandom42_33[198] = { + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x3b, 0xf5, 0x39, 0xdf, 0xa9, 0xc0, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00 +}; + +const uint8_t kMaskRandom42_34[204] = { + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x46, 0x11, 0x92, 0x30, 0x8c, 0x80, + 0x33, 0x0c, 0xc9, 0x98, 0x66, 0x40, + 0x10, 0xe4, 0x60, 0x87, 0x23, 0x00, + 0x0c, 0x69, 0x08, 0x63, 0x48, 0x40, + 0x28, 0x94, 0x29, 0x44, 0xa1, 0x40, + 0x94, 0x21, 0x34, 0xa1, 0x09, 0x80, + 0xc1, 0x02, 0x5e, 0x08, 0x12, 0xc0, + 0x3b, 0xf5, 0x39, 0xdf, 0xa9, 0xc0, + 0xf8, 0xbf, 0xf6, 0x76, 0x1b, 0x80 +}; + +const uint8_t kMaskRandom42_35[210] = { + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x5a, 0x56, 0x5a, 0xd2, 0xb2, 0xc0 +}; + +const uint8_t kMaskRandom42_36[216] = { + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x5a, 0x56, 0x5a, 0xd2, 0xb2, 0xc0, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x57, 0xc7, 0x03, 0xf9, 0xc6, 0x00 +}; + +const uint8_t kMaskRandom42_37[222] = { + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x5a, 0x56, 0x5a, 0xd2, 0xb2, 0xc0, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40 +}; + +const uint8_t kMaskRandom42_38[228] = { + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2c, 0x03, 0x21, 0x60, 0x19, 0x00, + 0x81, 0xa0, 0x1c, 0x0d, 0x00, 0xc0, + 0xa0, 0x68, 0x25, 0x03, 0x41, 0x00, + 0x05, 0x41, 0x50, 0x2a, 0x0a, 0x80, + 0x18, 0x90, 0xc0, 0xc4, 0x86, 0x00, + 0xc2, 0x06, 0x86, 0x10, 0x34, 0x00, + 0x22, 0x98, 0x09, 0x14, 0xc0, 0x40, + 0x50, 0x45, 0x0a, 0x82, 0x28, 0x40, + 0x5a, 0x56, 0x5a, 0xd2, 0xb2, 0xc0, + 0x05, 0x19, 0x55, 0xee, 0xe2, 0xc0 +}; + +const uint8_t kMaskRandom42_39[234] = { + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2a, 0x03, 0x31, 0x50, 0x19, 0x80 +}; + +const uint8_t kMaskRandom42_4[24] = { + 0xe6, 0x31, 0x37, 0x31, 0x89, 0x80, + 0x33, 0x8c, 0x59, 0x9c, 0x62, 0xc0, + 0x98, 0xd2, 0xcc, 0xc6, 0x96, 0x40, + 0x2d, 0x4b, 0x29, 0x6a, 0x59, 0x40 +}; + +const uint8_t kMaskRandom42_40[240] = { + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2a, 0x03, 0x31, 0x50, 0x19, 0x80, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0xf9, 0xdb, 0x5d, 0x7a, 0xd4, 0x40 +}; + +const uint8_t kMaskRandom42_41[246] = { + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2a, 0x03, 0x31, 0x50, 0x19, 0x80, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4c, 0x11, 0x92, 0x60, 0x8c, 0x80, + 0x51, 0x0c, 0xca, 0x88, 0x66, 0x40, + 0xa0, 0x66, 0x45, 0x03, 0x32, 0x00, + 0x04, 0xc1, 0x60, 0x26, 0x0b, 0x00, + 0x03, 0xa0, 0x28, 0x1d, 0x01, 0x40, + 0x86, 0x21, 0x14, 0x31, 0x08, 0x80, + 0x29, 0x10, 0x19, 0x48, 0x80, 0xc0, + 0x42, 0x42, 0xa2, 0x12, 0x15, 0x00, + 0x98, 0x1a, 0x04, 0xc0, 0xd0, 0x00, + 0x30, 0x84, 0x09, 0x84, 0x20, 0x40, + 0xdf, 0x4c, 0x16, 0xfa, 0x60, 0x80 +}; + +const uint8_t kMaskRandom42_42[252] = { + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4c, 0x11, 0x92, 0x60, 0x8c, 0x80, + 0x51, 0x0c, 0xca, 0x88, 0x66, 0x40, + 0xa0, 0x66, 0x45, 0x03, 0x32, 0x00, + 0x04, 0xc1, 0x60, 0x26, 0x0b, 0x00, + 0x03, 0xa0, 0x28, 0x1d, 0x01, 0x40, + 0x86, 0x21, 0x14, 0x31, 0x08, 0x80, + 0x29, 0x10, 0x19, 0x48, 0x80, 0xc0, + 0x42, 0x42, 0xa2, 0x12, 0x15, 0x00, + 0x98, 0x1a, 0x04, 0xc0, 0xd0, 0x00, + 0x30, 0x84, 0x09, 0x84, 0x20, 0x40, + 0xdf, 0x4c, 0x16, 0xfa, 0x60, 0x80, + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0xa0, 0x6a, 0x45, 0x03, 0x52, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x09, 0x80, + 0x03, 0xb4, 0x00, 0x1d, 0xa0, 0x00, + 0x86, 0x20, 0x94, 0x31, 0x04, 0x80, + 0x29, 0x08, 0x49, 0x48, 0x42, 0x40, + 0x42, 0x43, 0x0a, 0x12, 0x18, 0x40, + 0x98, 0x12, 0x84, 0xc0, 0x94, 0x00, + 0x30, 0x84, 0xa9, 0x84, 0x25, 0x40, + 0x4e, 0x11, 0x92, 0x70, 0x8c, 0x80, + 0xe3, 0x18, 0x9f, 0x18, 0xc4, 0xc0, + 0x81, 0xe3, 0x04, 0x0f, 0x18, 0x00, + 0x21, 0x40, 0x59, 0x0a, 0x02, 0xc0, + 0x52, 0x81, 0xe2, 0x94, 0x0f, 0x00, + 0xb4, 0x28, 0x25, 0xa1, 0x41, 0x00, + 0x26, 0x86, 0x29, 0x34, 0x31, 0x40, + 0x58, 0x64, 0x42, 0xc3, 0x22, 0x00, + 0x19, 0x9e, 0x00, 0xcc, 0xf0, 0x00, + 0x2a, 0x03, 0x31, 0x50, 0x19, 0x80, + 0xea, 0x9e, 0x23, 0xb3, 0x65, 0x00 +}; + +const uint8_t kMaskRandom42_5[30] = { + 0xce, 0x31, 0xb6, 0x71, 0x8d, 0x80, + 0x63, 0x98, 0xdb, 0x1c, 0xc6, 0xc0, + 0x98, 0xc7, 0x6c, 0xc6, 0x3b, 0x40, + 0x4d, 0x6b, 0x52, 0x6b, 0x5a, 0x80, + 0xb2, 0x6c, 0xad, 0x93, 0x65, 0x40 +}; + +const uint8_t kMaskRandom42_6[36] = { + 0x4c, 0x19, 0x12, 0x60, 0xc8, 0x80, + 0x51, 0x14, 0x52, 0x88, 0xa2, 0x80, + 0x20, 0xea, 0x09, 0x07, 0x50, 0x40, + 0x85, 0x41, 0x2c, 0x2a, 0x09, 0x40, + 0x06, 0x80, 0xd8, 0x34, 0x06, 0xc0, + 0x8a, 0x24, 0x34, 0x51, 0x21, 0x80 +}; + +const uint8_t kMaskRandom42_7[42] = { + 0xc6, 0x11, 0x96, 0x30, 0x8c, 0x80, + 0x33, 0x04, 0xc9, 0x98, 0x26, 0x40, + 0x18, 0x67, 0x40, 0xc3, 0x3a, 0x00, + 0x45, 0x42, 0xd2, 0x2a, 0x16, 0x80, + 0x12, 0xd4, 0x28, 0x96, 0xa1, 0x40, + 0xb4, 0x28, 0x35, 0xa1, 0x41, 0x80, + 0x29, 0x92, 0x19, 0x4c, 0x90, 0xc0 +}; + +const uint8_t kMaskRandom42_8[48] = { + 0x07, 0x0a, 0x70, 0x38, 0x53, 0x80, + 0x49, 0xa8, 0x2a, 0x4d, 0x41, 0x40, + 0xb0, 0x7a, 0x05, 0x83, 0xd0, 0x00, + 0x24, 0xc5, 0xc1, 0x26, 0x2e, 0x00, + 0x52, 0x80, 0xea, 0x94, 0x07, 0x40, + 0xc6, 0x31, 0x86, 0x31, 0x8c, 0x00, + 0x31, 0x94, 0x19, 0x8c, 0xa0, 0xc0, + 0x18, 0xc7, 0x08, 0xc6, 0x38, 0x40 +}; + +const uint8_t kMaskRandom42_9[54] = { + 0x4e, 0x11, 0x12, 0x70, 0x88, 0x80, + 0x62, 0x1a, 0x0b, 0x10, 0xd0, 0x40, + 0x80, 0xe9, 0x44, 0x07, 0x4a, 0x00, + 0xa1, 0x50, 0x55, 0x0a, 0x82, 0x80, + 0x53, 0x00, 0x6a, 0x98, 0x03, 0x40, + 0xa4, 0x24, 0x35, 0x21, 0x21, 0x80, + 0x16, 0xa0, 0x88, 0xb5, 0x04, 0x40, + 0x58, 0x45, 0x22, 0xc2, 0x29, 0x00, + 0x29, 0x86, 0x81, 0x4c, 0x34, 0x00 +}; + +const uint8_t kMaskRandom43_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 +}; + +const uint8_t kMaskRandom43_10[60] = { + 0x4c, 0x19, 0x16, 0x01, 0xc4, 0x40, + 0x51, 0x14, 0x51, 0x80, 0x71, 0x40, + 0xa0, 0x6a, 0x47, 0x40, 0x38, 0x00, + 0x04, 0xc1, 0x34, 0x28, 0x45, 0x40, + 0x03, 0xb4, 0x06, 0x84, 0x90, 0x80, + 0x86, 0x20, 0x94, 0x32, 0x82, 0x40, + 0x29, 0x08, 0x4a, 0x53, 0x40, 0x60, + 0x42, 0x43, 0x08, 0x0d, 0x03, 0xa0, + 0x98, 0x12, 0x82, 0x64, 0x0c, 0x80, + 0x30, 0x84, 0xab, 0x11, 0x20, 0x20 +}; + +const uint8_t kMaskRandom43_11[66] = { + 0xc6, 0x21, 0xa2, 0x32, 0x46, 0x40, + 0x23, 0x88, 0xc9, 0x99, 0x33, 0x20, + 0x1a, 0x45, 0x8c, 0xc8, 0x99, 0x00, + 0x24, 0xd3, 0x08, 0x2c, 0x05, 0x80, + 0x71, 0x10, 0x74, 0x05, 0x80, 0xa0, + 0x0e, 0x19, 0x14, 0x22, 0x84, 0x40, + 0x33, 0x14, 0x52, 0x03, 0x40, 0x60, + 0x10, 0xc3, 0x28, 0x54, 0x0a, 0x80, + 0x45, 0x68, 0x4b, 0x40, 0x68, 0x00, + 0x88, 0x84, 0xa8, 0x81, 0x10, 0x20, + 0xe0, 0x22, 0x91, 0x82, 0x30, 0x40 +}; + +const uint8_t kMaskRandom43_12[72] = { + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0xc6, 0x21, 0xa4, 0x34, 0x86, 0x80, + 0x23, 0x88, 0xc9, 0x19, 0x23, 0x20, + 0x1a, 0x45, 0x88, 0xb1, 0x16, 0x20, + 0x24, 0xd3, 0x0a, 0x61, 0x4c, 0x20, + 0x71, 0x10, 0x72, 0x0e, 0x41, 0xc0, + 0xa0, 0x65, 0x1f, 0xa0, 0xc4, 0xe0 +}; + +const uint8_t kMaskRandom43_13[78] = { + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60 +}; + +const uint8_t kMaskRandom43_14[84] = { + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x4d, 0xd0, 0xc6, 0x36, 0x57, 0x40 +}; + +const uint8_t kMaskRandom43_15[90] = { + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20 +}; + +const uint8_t kMaskRandom43_16[96] = { + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x3b, 0xf5, 0x3c, 0x36, 0x0a, 0x20 +}; + +const uint8_t kMaskRandom43_17[102] = { + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00 +}; + +const uint8_t kMaskRandom43_18[108] = { + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x5a, 0x56, 0x5f, 0x26, 0xa3, 0x60 +}; + +const uint8_t kMaskRandom43_19[114] = { + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0 +}; + +const uint8_t kMaskRandom43_2[12] = { + 0xee, 0x3b, 0x37, 0x66, 0xec, 0xc0, + 0x99, 0xe6, 0xec, 0xdd, 0x9b, 0xa0 +}; + +const uint8_t kMaskRandom43_20[120] = { + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2a, 0x03, 0x31, 0xda, 0x46, 0x20 +}; + +const uint8_t kMaskRandom43_21[126] = { + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4c, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x51, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0xa0, 0x66, 0x44, 0xc8, 0x99, 0x00, + 0x04, 0xc1, 0x60, 0x2c, 0x05, 0x80, + 0x03, 0xa0, 0x2c, 0x05, 0x80, 0xa0, + 0x86, 0x21, 0x14, 0x22, 0x84, 0x40, + 0x29, 0x10, 0x1a, 0x03, 0x40, 0x60, + 0x42, 0x42, 0xa0, 0x54, 0x0a, 0x80, + 0x98, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x30, 0x84, 0x08, 0x81, 0x10, 0x20, + 0xdf, 0x4c, 0x11, 0x82, 0x30, 0x40 +}; + +const uint8_t kMaskRandom43_22[132] = { + 0xc6, 0x21, 0xa2, 0x32, 0x46, 0x40, + 0x23, 0x88, 0xc9, 0x99, 0x33, 0x20, + 0x1a, 0x45, 0x8c, 0xc8, 0x99, 0x00, + 0x24, 0xd3, 0x08, 0x2c, 0x05, 0x80, + 0x71, 0x10, 0x74, 0x05, 0x80, 0xa0, + 0x0e, 0x19, 0x14, 0x22, 0x84, 0x40, + 0x33, 0x14, 0x52, 0x03, 0x40, 0x60, + 0x10, 0xc3, 0x28, 0x54, 0x0a, 0x80, + 0x45, 0x68, 0x4b, 0x40, 0x68, 0x00, + 0x88, 0x84, 0xa8, 0x81, 0x10, 0x20, + 0xe0, 0x22, 0x91, 0x82, 0x30, 0x40, + 0x4c, 0x19, 0x16, 0x01, 0xc4, 0x40, + 0x51, 0x14, 0x51, 0x80, 0x71, 0x40, + 0xa0, 0x6a, 0x47, 0x40, 0x38, 0x00, + 0x04, 0xc1, 0x34, 0x28, 0x45, 0x40, + 0x03, 0xb4, 0x06, 0x84, 0x90, 0x80, + 0x86, 0x20, 0x94, 0x32, 0x82, 0x40, + 0x29, 0x08, 0x4a, 0x53, 0x40, 0x60, + 0x42, 0x43, 0x08, 0x0d, 0x03, 0xa0, + 0x98, 0x12, 0x82, 0x64, 0x0c, 0x80, + 0x30, 0x84, 0xab, 0x11, 0x20, 0x20, + 0xfe, 0x2c, 0x85, 0xcc, 0x24, 0x80 +}; + +const uint8_t kMaskRandom43_23[138] = { + 0xc6, 0x21, 0xa2, 0x32, 0x46, 0x40, + 0x23, 0x88, 0xc9, 0x99, 0x33, 0x20, + 0x1a, 0x45, 0x8c, 0xc8, 0x99, 0x00, + 0x24, 0xd3, 0x08, 0x2c, 0x05, 0x80, + 0x71, 0x10, 0x74, 0x05, 0x80, 0xa0, + 0x0e, 0x19, 0x14, 0x22, 0x84, 0x40, + 0x33, 0x14, 0x52, 0x03, 0x40, 0x60, + 0x10, 0xc3, 0x28, 0x54, 0x0a, 0x80, + 0x45, 0x68, 0x4b, 0x40, 0x68, 0x00, + 0x88, 0x84, 0xa8, 0x81, 0x10, 0x20, + 0xe0, 0x22, 0x91, 0x82, 0x30, 0x40, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0xc6, 0x21, 0xa4, 0x34, 0x86, 0x80, + 0x23, 0x88, 0xc9, 0x19, 0x23, 0x20, + 0x1a, 0x45, 0x88, 0xb1, 0x16, 0x20, + 0x24, 0xd3, 0x0a, 0x61, 0x4c, 0x20, + 0x71, 0x10, 0x72, 0x0e, 0x41, 0xc0, + 0xa0, 0x65, 0x1f, 0xa0, 0xc4, 0xe0 +}; + +const uint8_t kMaskRandom43_24[144] = { + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0xc6, 0x21, 0xa4, 0x34, 0x86, 0x80, + 0x23, 0x88, 0xc9, 0x19, 0x23, 0x20, + 0x1a, 0x45, 0x88, 0xb1, 0x16, 0x20, + 0x24, 0xd3, 0x0a, 0x61, 0x4c, 0x20, + 0x71, 0x10, 0x72, 0x0e, 0x41, 0xc0, + 0xa0, 0x65, 0x1f, 0xa0, 0xc4, 0xe0, + 0xc6, 0x21, 0xa2, 0x32, 0x46, 0x40, + 0x23, 0x88, 0xc9, 0x99, 0x33, 0x20, + 0x1a, 0x45, 0x8c, 0xc8, 0x99, 0x00, + 0x24, 0xd3, 0x08, 0x2c, 0x05, 0x80, + 0x71, 0x10, 0x74, 0x05, 0x80, 0xa0, + 0x0e, 0x19, 0x14, 0x22, 0x84, 0x40, + 0x33, 0x14, 0x52, 0x03, 0x40, 0x60, + 0x10, 0xc3, 0x28, 0x54, 0x0a, 0x80, + 0x45, 0x68, 0x4b, 0x40, 0x68, 0x00, + 0x88, 0x84, 0xa8, 0x81, 0x10, 0x20, + 0xe0, 0x22, 0x91, 0x82, 0x30, 0x40, + 0xf9, 0xb1, 0x26, 0x6c, 0x51, 0xe0 +}; + +const uint8_t kMaskRandom43_25[150] = { + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0xc6, 0x21, 0xa4, 0x34, 0x86, 0x80, + 0x23, 0x88, 0xc9, 0x19, 0x23, 0x20, + 0x1a, 0x45, 0x88, 0xb1, 0x16, 0x20, + 0x24, 0xd3, 0x0a, 0x61, 0x4c, 0x20, + 0x71, 0x10, 0x72, 0x0e, 0x41, 0xc0, + 0xa0, 0x65, 0x1f, 0xa0, 0xc4, 0xe0, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60 +}; + +const uint8_t kMaskRandom43_26[156] = { + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0xc6, 0x21, 0xa4, 0x34, 0x86, 0x80, + 0x23, 0x88, 0xc9, 0x19, 0x23, 0x20, + 0x1a, 0x45, 0x88, 0xb1, 0x16, 0x20, + 0x24, 0xd3, 0x0a, 0x61, 0x4c, 0x20, + 0x71, 0x10, 0x72, 0x0e, 0x41, 0xc0, + 0xa0, 0x65, 0x1f, 0xa0, 0xc4, 0xe0, + 0xef, 0x84, 0x77, 0xca, 0x0d, 0x40 +}; + +const uint8_t kMaskRandom43_27[162] = { + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x4d, 0xd0, 0xc6, 0x36, 0x57, 0x40 +}; + +const uint8_t kMaskRandom43_28[168] = { + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x4d, 0xd0, 0xc6, 0x36, 0x57, 0x40, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x16, 0xc9, 0x53, 0x1e, 0xc4, 0x00 +}; + +const uint8_t kMaskRandom43_29[174] = { + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x4d, 0xd0, 0xc6, 0x36, 0x57, 0x40, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20 +}; + +const uint8_t kMaskRandom43_3[18] = { + 0xce, 0x32, 0xb6, 0x56, 0xca, 0xc0, + 0x55, 0xdc, 0x57, 0x8a, 0xf1, 0x40, + 0xa8, 0xed, 0x8d, 0xb1, 0xae, 0x20 +}; + +const uint8_t kMaskRandom43_30[180] = { + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x0e, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x33, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x10, 0xc3, 0x28, 0x65, 0x0c, 0xa0, + 0x45, 0x68, 0x4d, 0x09, 0xa1, 0x20, + 0x88, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0xe0, 0x22, 0x94, 0x52, 0x8a, 0x40, + 0x4d, 0xd0, 0xc6, 0x36, 0x57, 0x40, + 0x79, 0x4a, 0x8f, 0x42, 0x79, 0x40 +}; + +const uint8_t kMaskRandom43_31[186] = { + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x3b, 0xf5, 0x3c, 0x36, 0x0a, 0x20 +}; + +const uint8_t kMaskRandom43_32[192] = { + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x3b, 0xf5, 0x3c, 0x36, 0x0a, 0x20, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0xd1, 0xd1, 0x11, 0xa4, 0xed, 0xc0 +}; + +const uint8_t kMaskRandom43_33[198] = { + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x3b, 0xf5, 0x3c, 0x36, 0x0a, 0x20, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00 +}; + +const uint8_t kMaskRandom43_34[204] = { + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x46, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x33, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0x10, 0xe4, 0x64, 0x8c, 0x91, 0x80, + 0x0c, 0x69, 0x0d, 0x21, 0xa4, 0x20, + 0x28, 0x94, 0x2a, 0x85, 0x50, 0xa0, + 0x94, 0x21, 0x34, 0x26, 0x84, 0xc0, + 0xc1, 0x02, 0x58, 0x4b, 0x09, 0x60, + 0x3b, 0xf5, 0x3c, 0x36, 0x0a, 0x20, + 0x76, 0x81, 0x4d, 0x33, 0x66, 0x00 +}; + +const uint8_t kMaskRandom43_35[210] = { + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x5a, 0x56, 0x5f, 0x26, 0xa3, 0x60 +}; + +const uint8_t kMaskRandom43_36[216] = { + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x5a, 0x56, 0x5f, 0x26, 0xa3, 0x60, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0xa3, 0x85, 0x0a, 0xb5, 0x11, 0x60 +}; + +const uint8_t kMaskRandom43_37[222] = { + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x5a, 0x56, 0x5f, 0x26, 0xa3, 0x60, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0 +}; + +const uint8_t kMaskRandom43_38[228] = { + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2c, 0x03, 0x20, 0x64, 0x0c, 0x80, + 0x81, 0xa0, 0x1c, 0x03, 0x80, 0x60, + 0xa0, 0x68, 0x25, 0x04, 0xa0, 0x80, + 0x05, 0x41, 0x50, 0x2a, 0x05, 0x40, + 0x18, 0x90, 0xc2, 0x18, 0x43, 0x00, + 0xc2, 0x06, 0x80, 0xd0, 0x1a, 0x00, + 0x22, 0x98, 0x0b, 0x01, 0x60, 0x20, + 0x50, 0x45, 0x08, 0xa1, 0x14, 0x20, + 0x5a, 0x56, 0x5f, 0x26, 0xa3, 0x60, + 0x9a, 0x16, 0x97, 0x21, 0xb9, 0x80 +}; + +const uint8_t kMaskRandom43_39[234] = { + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2a, 0x03, 0x31, 0xda, 0x46, 0x20 +}; + +const uint8_t kMaskRandom43_4[24] = { + 0xe6, 0x31, 0x36, 0x26, 0xc4, 0xc0, + 0x33, 0x8c, 0x59, 0x8b, 0x31, 0x60, + 0x98, 0xd2, 0xca, 0x59, 0x4b, 0x20, + 0x2d, 0x4b, 0x29, 0x65, 0x2c, 0xa0 +}; + +const uint8_t kMaskRandom43_40[240] = { + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2a, 0x03, 0x31, 0xda, 0x46, 0x20, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x3a, 0xab, 0x77, 0x63, 0xef, 0x60 +}; + +const uint8_t kMaskRandom43_41[246] = { + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2a, 0x03, 0x31, 0xda, 0x46, 0x20, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4c, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x51, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0xa0, 0x66, 0x44, 0xc8, 0x99, 0x00, + 0x04, 0xc1, 0x60, 0x2c, 0x05, 0x80, + 0x03, 0xa0, 0x2c, 0x05, 0x80, 0xa0, + 0x86, 0x21, 0x14, 0x22, 0x84, 0x40, + 0x29, 0x10, 0x1a, 0x03, 0x40, 0x60, + 0x42, 0x42, 0xa0, 0x54, 0x0a, 0x80, + 0x98, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x30, 0x84, 0x08, 0x81, 0x10, 0x20, + 0xdf, 0x4c, 0x11, 0x82, 0x30, 0x40 +}; + +const uint8_t kMaskRandom43_42[252] = { + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4c, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x51, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0xa0, 0x66, 0x44, 0xc8, 0x99, 0x00, + 0x04, 0xc1, 0x60, 0x2c, 0x05, 0x80, + 0x03, 0xa0, 0x2c, 0x05, 0x80, 0xa0, + 0x86, 0x21, 0x14, 0x22, 0x84, 0x40, + 0x29, 0x10, 0x1a, 0x03, 0x40, 0x60, + 0x42, 0x42, 0xa0, 0x54, 0x0a, 0x80, + 0x98, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x30, 0x84, 0x08, 0x81, 0x10, 0x20, + 0xdf, 0x4c, 0x11, 0x82, 0x30, 0x40, + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4e, 0x11, 0x92, 0x32, 0x46, 0x40, + 0xe3, 0x18, 0x9b, 0x13, 0x62, 0x60, + 0x81, 0xe3, 0x04, 0x60, 0x8c, 0x00, + 0x21, 0x40, 0x58, 0x0b, 0x01, 0x60, + 0x52, 0x81, 0xe0, 0x3c, 0x07, 0x80, + 0xb4, 0x28, 0x25, 0x04, 0xa0, 0x80, + 0x26, 0x86, 0x28, 0xc5, 0x18, 0xa0, + 0x58, 0x64, 0x44, 0x88, 0x91, 0x00, + 0x19, 0x9e, 0x03, 0xc0, 0x78, 0x00, + 0x2a, 0x03, 0x31, 0xda, 0x46, 0x20, + 0x26, 0x84, 0x10, 0xcd, 0xf7, 0x60 +}; + +const uint8_t kMaskRandom43_43[258] = { + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0xa0, 0x6a, 0x45, 0x48, 0xa9, 0x00, + 0x04, 0xc1, 0x30, 0x26, 0x04, 0xc0, + 0x03, 0xb4, 0x06, 0x80, 0xd0, 0x00, + 0x86, 0x20, 0x94, 0x12, 0x82, 0x40, + 0x29, 0x08, 0x49, 0x09, 0x21, 0x20, + 0x42, 0x43, 0x08, 0x61, 0x0c, 0x20, + 0x98, 0x12, 0x82, 0x50, 0x4a, 0x00, + 0x30, 0x84, 0xa8, 0x95, 0x12, 0xa0, + 0x4c, 0x11, 0x92, 0x32, 0x46, 0x40, + 0x51, 0x0c, 0xc9, 0x99, 0x33, 0x20, + 0xa0, 0x66, 0x44, 0xc8, 0x99, 0x00, + 0x04, 0xc1, 0x60, 0x2c, 0x05, 0x80, + 0x03, 0xa0, 0x2c, 0x05, 0x80, 0xa0, + 0x86, 0x21, 0x14, 0x22, 0x84, 0x40, + 0x29, 0x10, 0x1a, 0x03, 0x40, 0x60, + 0x42, 0x42, 0xa0, 0x54, 0x0a, 0x80, + 0x98, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x30, 0x84, 0x08, 0x81, 0x10, 0x20, + 0xdf, 0x4c, 0x11, 0x82, 0x30, 0x40, + 0x4c, 0x19, 0x12, 0x32, 0x46, 0x40, + 0x51, 0x14, 0x51, 0x99, 0x33, 0x20, + 0xa0, 0x6a, 0x44, 0xc8, 0x99, 0x00, + 0x04, 0xc1, 0x30, 0x2c, 0x05, 0x80, + 0x03, 0xb4, 0x04, 0x05, 0x80, 0xa0, + 0x86, 0x20, 0x94, 0x22, 0x84, 0x40, + 0x29, 0x08, 0x4a, 0x03, 0x40, 0x60, + 0x42, 0x43, 0x08, 0x54, 0x0a, 0x80, + 0x98, 0x12, 0x83, 0x40, 0x68, 0x00, + 0x30, 0x84, 0xa8, 0x81, 0x10, 0x20, + 0x4c, 0x11, 0x91, 0x82, 0x30, 0x40, + 0x51, 0x0c, 0xcb, 0x22, 0x64, 0x40, + 0xa0, 0x66, 0x42, 0x8a, 0x51, 0x40, + 0x04, 0xc1, 0x65, 0x48, 0xa9, 0x00, + 0x03, 0xa0, 0x28, 0x26, 0x04, 0xc0, + 0x86, 0x21, 0x16, 0x80, 0xd0, 0x00, + 0x29, 0x10, 0x1c, 0x12, 0x82, 0x40, + 0x42, 0x42, 0xa1, 0x09, 0x21, 0x20, + 0x98, 0x1a, 0x00, 0x61, 0x0c, 0x20, + 0x30, 0x84, 0x0a, 0x50, 0x4a, 0x00, + 0xdf, 0x4c, 0x10, 0x95, 0x12, 0xa0, + 0x72, 0x06, 0x94, 0xf6, 0x74, 0x40 +}; + +const uint8_t kMaskRandom43_5[30] = { + 0xce, 0x31, 0xb6, 0x36, 0xc6, 0xc0, + 0x63, 0x98, 0xdb, 0x1b, 0x63, 0x60, + 0x98, 0xc7, 0x68, 0xed, 0x1d, 0xa0, + 0x4d, 0x6b, 0x55, 0x6a, 0xad, 0x40, + 0xb2, 0x6c, 0xad, 0x95, 0xb2, 0xa0 +}; + +const uint8_t kMaskRandom43_6[36] = { + 0x4c, 0x19, 0x13, 0x22, 0x64, 0x40, + 0x51, 0x14, 0x52, 0x8a, 0x51, 0x40, + 0x20, 0xea, 0x0d, 0x41, 0xa8, 0x20, + 0x85, 0x41, 0x2e, 0x25, 0x04, 0xa0, + 0x06, 0x80, 0xd8, 0x1b, 0x03, 0x60, + 0x8a, 0x24, 0x34, 0x86, 0x90, 0xc0 +}; + +const uint8_t kMaskRandom43_7[42] = { + 0xc6, 0x11, 0x96, 0x32, 0x46, 0x40, + 0x33, 0x04, 0xc8, 0x99, 0x33, 0x20, + 0x18, 0x67, 0x44, 0x68, 0x9d, 0x00, + 0x45, 0x42, 0xd4, 0x5a, 0x0b, 0x40, + 0x12, 0xd4, 0x2a, 0x95, 0x50, 0xa0, + 0xb4, 0x28, 0x35, 0x16, 0xa0, 0xc0, + 0x29, 0x92, 0x1b, 0x0d, 0x41, 0x60 +}; + +const uint8_t kMaskRandom43_8[48] = { + 0x07, 0x0a, 0x71, 0x44, 0x29, 0xc0, + 0x49, 0xa8, 0x29, 0x0f, 0xa0, 0x20, + 0xb0, 0x7a, 0x07, 0x48, 0xe8, 0x00, + 0x24, 0xc5, 0xc0, 0xb8, 0x17, 0x00, + 0x52, 0x80, 0xec, 0x1d, 0x02, 0xa0, + 0xc6, 0x31, 0x82, 0x30, 0xc7, 0x40, + 0x31, 0x94, 0x1a, 0x83, 0x50, 0x60, + 0x18, 0xc7, 0x08, 0xe1, 0x1c, 0x20 +}; + +const uint8_t kMaskRandom43_9[54] = { + 0x4e, 0x11, 0x12, 0x22, 0x46, 0x40, + 0x62, 0x1a, 0x09, 0x41, 0x68, 0x60, + 0x80, 0xe9, 0x41, 0x28, 0xa5, 0x00, + 0xa1, 0x50, 0x52, 0xc8, 0x51, 0x00, + 0x53, 0x00, 0x68, 0x1d, 0x01, 0xa0, + 0xa4, 0x24, 0x36, 0x06, 0x80, 0xc0, + 0x16, 0xa0, 0x8d, 0x11, 0x82, 0x20, + 0x58, 0x45, 0x20, 0xa4, 0x16, 0x80, + 0x29, 0x86, 0x84, 0xd0, 0x1c, 0x00 +}; + +const uint8_t kMaskRandom44_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 +}; + +const uint8_t kMaskRandom44_10[60] = { + 0xc0, 0x38, 0x8b, 0x00, 0xe2, 0x20, + 0x30, 0x0e, 0x28, 0xc0, 0x38, 0xa0, + 0xe8, 0x07, 0x03, 0xa0, 0x1c, 0x00, + 0x85, 0x08, 0xaa, 0x14, 0x22, 0xa0, + 0xd0, 0x92, 0x13, 0x42, 0x48, 0x40, + 0x86, 0x50, 0x4a, 0x19, 0x41, 0x20, + 0x4a, 0x68, 0x0d, 0x29, 0xa0, 0x30, + 0x01, 0xa0, 0x74, 0x06, 0x81, 0xd0, + 0x4c, 0x81, 0x91, 0x32, 0x06, 0x40, + 0x62, 0x24, 0x05, 0x88, 0x90, 0x10 +}; + +const uint8_t kMaskRandom44_11[66] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20 +}; + +const uint8_t kMaskRandom44_12[72] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x86, 0x90, 0xd2, 0x1a, 0x43, 0x40, + 0x23, 0x24, 0x64, 0x8c, 0x91, 0x90, + 0x16, 0x22, 0xc4, 0x58, 0x8b, 0x10, + 0x4c, 0x29, 0x85, 0x30, 0xa6, 0x10, + 0x41, 0xc8, 0x39, 0x07, 0x20, 0xe0, + 0xf4, 0x18, 0x9f, 0xd0, 0x62, 0x70 +}; + +const uint8_t kMaskRandom44_13[78] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0 +}; + +const uint8_t kMaskRandom44_14[84] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0xc6, 0xca, 0xeb, 0x1b, 0x2b, 0xa0 +}; + +const uint8_t kMaskRandom44_15[90] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10 +}; + +const uint8_t kMaskRandom44_16[96] = { + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x86, 0xc1, 0x46, 0x1b, 0x05, 0x10 +}; + +const uint8_t kMaskRandom44_17[102] = { + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00 +}; + +const uint8_t kMaskRandom44_18[108] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0xe4, 0xd4, 0x6f, 0x93, 0x51, 0xb0 +}; + +const uint8_t kMaskRandom44_19[114] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50 +}; + +const uint8_t kMaskRandom44_2[12] = { + 0xec, 0xdd, 0x9b, 0xb3, 0x76, 0x60, + 0x9b, 0xb3, 0x76, 0x6e, 0xcd, 0xd0 +}; + +const uint8_t kMaskRandom44_20[120] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x3b, 0x48, 0xc4, 0xed, 0x23, 0x10 +}; + +const uint8_t kMaskRandom44_21[126] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20 +}; + +const uint8_t kMaskRandom44_22[132] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x9e, 0xce, 0x8a, 0x7b, 0x3a, 0x20 +}; + +const uint8_t kMaskRandom44_23[138] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x86, 0x90, 0xd2, 0x1a, 0x43, 0x40, + 0x23, 0x24, 0x64, 0x8c, 0x91, 0x90, + 0x16, 0x22, 0xc4, 0x58, 0x8b, 0x10, + 0x4c, 0x29, 0x85, 0x30, 0xa6, 0x10, + 0x41, 0xc8, 0x39, 0x07, 0x20, 0xe0, + 0xf4, 0x18, 0x9f, 0xd0, 0x62, 0x70 +}; + +const uint8_t kMaskRandom44_24[144] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x86, 0x90, 0xd2, 0x1a, 0x43, 0x40, + 0x23, 0x24, 0x64, 0x8c, 0x91, 0x90, + 0x16, 0x22, 0xc4, 0x58, 0x8b, 0x10, + 0x4c, 0x29, 0x85, 0x30, 0xa6, 0x10, + 0x41, 0xc8, 0x39, 0x07, 0x20, 0xe0, + 0xf4, 0x18, 0x9f, 0xd0, 0x62, 0x70, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0x15, 0x0f, 0x44, 0x6d, 0x9d, 0xa0 +}; + +const uint8_t kMaskRandom44_25[150] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x86, 0x90, 0xd2, 0x1a, 0x43, 0x40, + 0x23, 0x24, 0x64, 0x8c, 0x91, 0x90, + 0x16, 0x22, 0xc4, 0x58, 0x8b, 0x10, + 0x4c, 0x29, 0x85, 0x30, 0xa6, 0x10, + 0x41, 0xc8, 0x39, 0x07, 0x20, 0xe0, + 0xf4, 0x18, 0x9f, 0xd0, 0x62, 0x70, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0 +}; + +const uint8_t kMaskRandom44_26[156] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x86, 0x90, 0xd2, 0x1a, 0x43, 0x40, + 0x23, 0x24, 0x64, 0x8c, 0x91, 0x90, + 0x16, 0x22, 0xc4, 0x58, 0x8b, 0x10, + 0x4c, 0x29, 0x85, 0x30, 0xa6, 0x10, + 0x41, 0xc8, 0x39, 0x07, 0x20, 0xe0, + 0xf4, 0x18, 0x9f, 0xd0, 0x62, 0x70, + 0x02, 0xcb, 0x64, 0xb8, 0x55, 0x80 +}; + +const uint8_t kMaskRandom44_27[162] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0xc6, 0xca, 0xeb, 0x1b, 0x2b, 0xa0 +}; + +const uint8_t kMaskRandom44_28[168] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0xc6, 0xca, 0xeb, 0x1b, 0x2b, 0xa0, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x66, 0x26, 0x6c, 0x91, 0xc7, 0x20 +}; + +const uint8_t kMaskRandom44_29[174] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0xc6, 0xca, 0xeb, 0x1b, 0x2b, 0xa0, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10 +}; + +const uint8_t kMaskRandom44_3[18] = { + 0xca, 0xd9, 0x5b, 0x2b, 0x65, 0x60, + 0xf1, 0x5e, 0x2b, 0xc5, 0x78, 0xa0, + 0xb6, 0x35, 0xc6, 0xd8, 0xd7, 0x10 +}; + +const uint8_t kMaskRandom44_30[180] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0x0c, 0xa1, 0x94, 0x32, 0x86, 0x50, + 0xa1, 0x34, 0x26, 0x84, 0xd0, 0x90, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x8a, 0x51, 0x4a, 0x29, 0x45, 0x20, + 0xc6, 0xca, 0xeb, 0x1b, 0x2b, 0xa0, + 0x60, 0xf4, 0x75, 0x84, 0x90, 0xc0 +}; + +const uint8_t kMaskRandom44_31[186] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x86, 0xc1, 0x46, 0x1b, 0x05, 0x10 +}; + +const uint8_t kMaskRandom44_32[192] = { + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x86, 0xc1, 0x46, 0x1b, 0x05, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x3e, 0x39, 0x86, 0x5c, 0xd9, 0xd0 +}; + +const uint8_t kMaskRandom44_33[198] = { + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x86, 0xc1, 0x46, 0x1b, 0x05, 0x10, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00 +}; + +const uint8_t kMaskRandom44_34[204] = { + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x91, 0x92, 0x32, 0x46, 0x48, 0xc0, + 0xa4, 0x34, 0x86, 0x90, 0xd2, 0x10, + 0x50, 0xaa, 0x15, 0x42, 0xa8, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x42, 0x60, + 0x09, 0x61, 0x2c, 0x25, 0x84, 0xb0, + 0x86, 0xc1, 0x46, 0x1b, 0x05, 0x10, + 0xb5, 0xc7, 0xe8, 0x0c, 0xb9, 0x90 +}; + +const uint8_t kMaskRandom44_35[210] = { + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0xe4, 0xd4, 0x6f, 0x93, 0x51, 0xb0 +}; + +const uint8_t kMaskRandom44_36[216] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0xe4, 0xd4, 0x6f, 0x93, 0x51, 0xb0, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0xa6, 0x92, 0x01, 0x65, 0x91, 0x20 +}; + +const uint8_t kMaskRandom44_37[222] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0xe4, 0xd4, 0x6f, 0x93, 0x51, 0xb0, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50 +}; + +const uint8_t kMaskRandom44_38[228] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x0c, 0x81, 0x90, 0x32, 0x06, 0x40, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x30, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x05, 0x40, 0xa8, 0x15, 0x02, 0xa0, + 0x43, 0x08, 0x61, 0x0c, 0x21, 0x80, + 0x1a, 0x03, 0x40, 0x68, 0x0d, 0x00, + 0x60, 0x2c, 0x05, 0x80, 0xb0, 0x10, + 0x14, 0x22, 0x84, 0x50, 0x8a, 0x10, + 0xe4, 0xd4, 0x6f, 0x93, 0x51, 0xb0, + 0x43, 0x64, 0xf2, 0xe5, 0x5d, 0x10 +}; + +const uint8_t kMaskRandom44_39[234] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x3b, 0x48, 0xc4, 0xed, 0x23, 0x10 +}; + +const uint8_t kMaskRandom44_4[24] = { + 0xc4, 0xd8, 0x9b, 0x13, 0x62, 0x60, + 0x31, 0x66, 0x2c, 0xc5, 0x98, 0xb0, + 0x4b, 0x29, 0x65, 0x2c, 0xa5, 0x90, + 0x2c, 0xa5, 0x94, 0xb2, 0x96, 0x50 +}; + +const uint8_t kMaskRandom44_40[240] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x3b, 0x48, 0xc4, 0xed, 0x23, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0xd8, 0x2a, 0x16, 0x26, 0x51, 0x40 +}; + +const uint8_t kMaskRandom44_41[246] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x3b, 0x48, 0xc4, 0xed, 0x23, 0x10, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20 +}; + +const uint8_t kMaskRandom44_42[252] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x62, 0x6c, 0x4d, 0x89, 0xb1, 0x30, + 0x8c, 0x11, 0x82, 0x30, 0x46, 0x00, + 0x01, 0x60, 0x2c, 0x05, 0x80, 0xb0, + 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, + 0xa0, 0x94, 0x12, 0x82, 0x50, 0x40, + 0x18, 0xa3, 0x14, 0x62, 0x8c, 0x50, + 0x91, 0x12, 0x22, 0x44, 0x48, 0x80, + 0x78, 0x0f, 0x01, 0xe0, 0x3c, 0x00, + 0x3b, 0x48, 0xc4, 0xed, 0x23, 0x10, + 0xd9, 0xc1, 0x6f, 0xa8, 0x1c, 0x90 +}; + +const uint8_t kMaskRandom44_43[258] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x9e, 0xce, 0x8a, 0x7b, 0x3a, 0x20 +}; + +const uint8_t kMaskRandom44_44[264] = { + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x9e, 0xce, 0x8a, 0x7b, 0x3a, 0x20, + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa9, 0x15, 0x22, 0xa4, 0x54, 0x80, + 0x04, 0xc0, 0x98, 0x13, 0x02, 0x60, + 0xd0, 0x1a, 0x03, 0x40, 0x68, 0x00, + 0x82, 0x50, 0x4a, 0x09, 0x41, 0x20, + 0x21, 0x24, 0x24, 0x84, 0x90, 0x90, + 0x0c, 0x21, 0x84, 0x30, 0x86, 0x10, + 0x4a, 0x09, 0x41, 0x28, 0x25, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0x89, 0x50, + 0x46, 0x48, 0xc9, 0x19, 0x23, 0x20, + 0x33, 0x26, 0x64, 0xcc, 0x99, 0x90, + 0x99, 0x13, 0x22, 0x64, 0x4c, 0x80, + 0x05, 0x80, 0xb0, 0x16, 0x02, 0xc0, + 0x80, 0xb0, 0x16, 0x02, 0xc0, 0x50, + 0x84, 0x50, 0x8a, 0x11, 0x42, 0x20, + 0x40, 0x68, 0x0d, 0x01, 0xa0, 0x30, + 0x0a, 0x81, 0x50, 0x2a, 0x05, 0x40, + 0x68, 0x0d, 0x01, 0xa0, 0x34, 0x00, + 0x10, 0x22, 0x04, 0x40, 0x88, 0x10, + 0x30, 0x46, 0x08, 0xc1, 0x18, 0x20, + 0xb5, 0x1c, 0x1c, 0x21, 0xac, 0xa0 +}; + +const uint8_t kMaskRandom44_5[30] = { + 0xc6, 0xd8, 0xdb, 0x1b, 0x63, 0x60, + 0x63, 0x6c, 0x6d, 0x8d, 0xb1, 0xb0, + 0x1d, 0xa3, 0xb4, 0x76, 0x8e, 0xd0, + 0xad, 0x55, 0xaa, 0xb5, 0x56, 0xa0, + 0xb2, 0xb6, 0x56, 0xca, 0xd9, 0x50 +}; + +const uint8_t kMaskRandom44_6[36] = { + 0x64, 0x4c, 0x89, 0x91, 0x32, 0x20, + 0x51, 0x4a, 0x29, 0x45, 0x28, 0xa0, + 0xa8, 0x35, 0x06, 0xa0, 0xd4, 0x10, + 0xc4, 0xa0, 0x97, 0x12, 0x82, 0x50, + 0x03, 0x60, 0x6c, 0x0d, 0x81, 0xb0, + 0x90, 0xd2, 0x1a, 0x43, 0x48, 0x60 +}; + +const uint8_t kMaskRandom44_7[42] = { + 0xc6, 0x48, 0xcb, 0x19, 0x23, 0x20, + 0x13, 0x26, 0x64, 0x4c, 0x99, 0x90, + 0x8d, 0x13, 0xa2, 0x34, 0x4e, 0x80, + 0x8b, 0x41, 0x6a, 0x2d, 0x05, 0xa0, + 0x52, 0xaa, 0x15, 0x4a, 0xa8, 0x50, + 0xa2, 0xd4, 0x1a, 0x8b, 0x50, 0x60, + 0x61, 0xa8, 0x2d, 0x86, 0xa0, 0xb0 +}; + +const uint8_t kMaskRandom44_8[48] = { + 0x28, 0x85, 0x38, 0xa2, 0x14, 0xe0, + 0x21, 0xf4, 0x04, 0x87, 0xd0, 0x10, + 0xe9, 0x1d, 0x03, 0xa4, 0x74, 0x00, + 0x17, 0x02, 0xe0, 0x5c, 0x0b, 0x80, + 0x83, 0xa0, 0x56, 0x0e, 0x81, 0x50, + 0x46, 0x18, 0xe9, 0x18, 0x63, 0xa0, + 0x50, 0x6a, 0x0d, 0x41, 0xa8, 0x30, + 0x1c, 0x23, 0x84, 0x70, 0x8e, 0x10 +}; + +const uint8_t kMaskRandom44_9[54] = { + 0x44, 0x48, 0xc9, 0x11, 0x23, 0x20, + 0x28, 0x2d, 0x0c, 0xa0, 0xb4, 0x30, + 0x25, 0x14, 0xa0, 0x94, 0x52, 0x80, + 0x59, 0x0a, 0x21, 0x64, 0x28, 0x80, + 0x03, 0xa0, 0x34, 0x0e, 0x80, 0xd0, + 0xc0, 0xd0, 0x1b, 0x03, 0x40, 0x60, + 0xa2, 0x30, 0x46, 0x88, 0xc1, 0x10, + 0x14, 0x82, 0xd0, 0x52, 0x0b, 0x40, + 0x9a, 0x03, 0x82, 0x68, 0x0e, 0x00 +}; + +const uint8_t kMaskRandom45_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 +}; + +const uint8_t kMaskRandom45_10[60] = { + 0xc0, 0x38, 0x89, 0x91, 0x28, 0xa0, + 0x30, 0x0e, 0x29, 0x45, 0x22, 0x88, + 0xe8, 0x07, 0x02, 0xa4, 0x40, 0x68, + 0x85, 0x08, 0xa8, 0x13, 0x12, 0x10, + 0xd0, 0x92, 0x13, 0x40, 0x05, 0x10, + 0x86, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x4a, 0x68, 0x0c, 0x84, 0xdc, 0x00, + 0x01, 0xa0, 0x74, 0x30, 0x84, 0x88, + 0x4c, 0x81, 0x91, 0x28, 0x2b, 0x00, + 0x62, 0x24, 0x04, 0x4a, 0xd1, 0x40 +}; + +const uint8_t kMaskRandom45_11[66] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10 +}; + +const uint8_t kMaskRandom45_12[72] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x86, 0x90, 0xd2, 0x1a, 0x29, 0xb0, + 0x23, 0x24, 0x64, 0x8c, 0xb2, 0x10, + 0x16, 0x22, 0xc4, 0x58, 0x86, 0x60, + 0x4c, 0x29, 0x85, 0x30, 0xc1, 0x50, + 0x41, 0xc8, 0x39, 0x07, 0x04, 0x98, + 0xf4, 0x18, 0x9c, 0x65, 0x5b, 0x90 +}; + +const uint8_t kMaskRandom45_13[78] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30 +}; + +const uint8_t kMaskRandom45_14[84] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0xc6, 0xca, 0xea, 0x70, 0xfe, 0xc8 +}; + +const uint8_t kMaskRandom45_15[90] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80 +}; + +const uint8_t kMaskRandom45_16[96] = { + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x86, 0xc1, 0x47, 0xeb, 0x67, 0xd0 +}; + +const uint8_t kMaskRandom45_17[102] = { + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70 +}; + +const uint8_t kMaskRandom45_18[108] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0xe4, 0xd4, 0x6e, 0x08, 0xc9, 0x58 +}; + +const uint8_t kMaskRandom45_19[114] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40 +}; + +const uint8_t kMaskRandom45_2[12] = { + 0xec, 0xdd, 0x9b, 0xb3, 0x76, 0x60, + 0x9b, 0xb3, 0x76, 0x6e, 0xc9, 0xd8 +}; + +const uint8_t kMaskRandom45_20[120] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x3b, 0x48, 0xc7, 0x6d, 0x29, 0xe8 +}; + +const uint8_t kMaskRandom45_21[126] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10 +}; + +const uint8_t kMaskRandom45_22[132] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x9e, 0xce, 0x8b, 0xaa, 0x34, 0x68 +}; + +const uint8_t kMaskRandom45_23[138] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x86, 0x90, 0xd2, 0x1a, 0x29, 0xb0, + 0x23, 0x24, 0x64, 0x8c, 0xb2, 0x10, + 0x16, 0x22, 0xc4, 0x58, 0x86, 0x60, + 0x4c, 0x29, 0x85, 0x30, 0xc1, 0x50, + 0x41, 0xc8, 0x39, 0x07, 0x04, 0x98, + 0xf4, 0x18, 0x9c, 0x65, 0x5b, 0x90 +}; + +const uint8_t kMaskRandom45_24[144] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x86, 0x90, 0xd2, 0x1a, 0x29, 0xb0, + 0x23, 0x24, 0x64, 0x8c, 0xb2, 0x10, + 0x16, 0x22, 0xc4, 0x58, 0x86, 0x60, + 0x4c, 0x29, 0x85, 0x30, 0xc1, 0x50, + 0x41, 0xc8, 0x39, 0x07, 0x04, 0x98, + 0xf4, 0x18, 0x9c, 0x65, 0x5b, 0x90, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x95, 0x91, 0xad, 0xd9, 0x86, 0x98 +}; + +const uint8_t kMaskRandom45_25[150] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x86, 0x90, 0xd2, 0x1a, 0x29, 0xb0, + 0x23, 0x24, 0x64, 0x8c, 0xb2, 0x10, + 0x16, 0x22, 0xc4, 0x58, 0x86, 0x60, + 0x4c, 0x29, 0x85, 0x30, 0xc1, 0x50, + 0x41, 0xc8, 0x39, 0x07, 0x04, 0x98, + 0xf4, 0x18, 0x9c, 0x65, 0x5b, 0x90, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30 +}; + +const uint8_t kMaskRandom45_26[156] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x86, 0x90, 0xd2, 0x1a, 0x29, 0xb0, + 0x23, 0x24, 0x64, 0x8c, 0xb2, 0x10, + 0x16, 0x22, 0xc4, 0x58, 0x86, 0x60, + 0x4c, 0x29, 0x85, 0x30, 0xc1, 0x50, + 0x41, 0xc8, 0x39, 0x07, 0x04, 0x98, + 0xf4, 0x18, 0x9c, 0x65, 0x5b, 0x90, + 0xb0, 0xfd, 0xb2, 0xf3, 0x8a, 0xc0 +}; + +const uint8_t kMaskRandom45_27[162] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0xc6, 0xca, 0xea, 0x70, 0xfe, 0xc8 +}; + +const uint8_t kMaskRandom45_28[168] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0xc6, 0xca, 0xea, 0x70, 0xfe, 0xc8, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x44, 0x46, 0x28, 0xfb, 0x66, 0x80 +}; + +const uint8_t kMaskRandom45_29[174] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0xc6, 0xca, 0xea, 0x70, 0xfe, 0xc8, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80 +}; + +const uint8_t kMaskRandom45_3[18] = { + 0xca, 0xd9, 0x5b, 0x2b, 0x4d, 0x90, + 0xf1, 0x5e, 0x2b, 0xc5, 0x24, 0xe8, + 0xb6, 0x35, 0xc5, 0xd8, 0x9f, 0x40 +}; + +const uint8_t kMaskRandom45_30[180] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0x0c, 0xa1, 0x94, 0x32, 0x90, 0xc0, + 0xa1, 0x34, 0x26, 0x84, 0x89, 0x18, + 0x12, 0xa2, 0x54, 0x4a, 0x84, 0x70, + 0x8a, 0x51, 0x4a, 0x29, 0x17, 0x00, + 0xc6, 0xca, 0xea, 0x70, 0xfe, 0xc8, + 0x1c, 0xc9, 0x43, 0x25, 0xa7, 0x00 +}; + +const uint8_t kMaskRandom45_31[186] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x86, 0xc1, 0x47, 0xeb, 0x67, 0xd0 +}; + +const uint8_t kMaskRandom45_32[192] = { + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x86, 0xc1, 0x47, 0xeb, 0x67, 0xd0, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x40, 0x7e, 0xc1, 0x30, 0x29, 0x50 +}; + +const uint8_t kMaskRandom45_33[198] = { + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x86, 0xc1, 0x47, 0xeb, 0x67, 0xd0, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70 +}; + +const uint8_t kMaskRandom45_34[204] = { + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x91, 0x92, 0x32, 0x46, 0x48, 0x48, + 0xa4, 0x34, 0x86, 0x90, 0x81, 0x28, + 0x50, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0x84, 0xd0, 0x9a, 0x13, 0x16, 0x00, + 0x09, 0x61, 0x2c, 0x25, 0xc4, 0x30, + 0x86, 0xc1, 0x47, 0xeb, 0x67, 0xd0, + 0x1f, 0x78, 0x45, 0x5e, 0x46, 0x50 +}; + +const uint8_t kMaskRandom45_35[210] = { + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0xe4, 0xd4, 0x6e, 0x08, 0xc9, 0x58 +}; + +const uint8_t kMaskRandom45_36[216] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0xe4, 0xd4, 0x6e, 0x08, 0xc9, 0x58, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0xd0, 0x1a, 0xf0, 0x14, 0xf0, 0xe8 +}; + +const uint8_t kMaskRandom45_37[222] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0xe4, 0xd4, 0x6e, 0x08, 0xc9, 0x58, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40 +}; + +const uint8_t kMaskRandom45_38[228] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x0c, 0x81, 0x90, 0x32, 0x10, 0x30, + 0x80, 0x70, 0x0e, 0x01, 0xc0, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x21, 0x20, + 0x05, 0x40, 0xa8, 0x15, 0x00, 0xc8, + 0x43, 0x08, 0x61, 0x0c, 0x0a, 0x08, + 0x1a, 0x03, 0x40, 0x68, 0x05, 0x40, + 0x60, 0x2c, 0x05, 0x80, 0x9c, 0x00, + 0x14, 0x22, 0x84, 0x50, 0xe2, 0x80, + 0xe4, 0xd4, 0x6e, 0x08, 0xc9, 0x58, + 0x04, 0x67, 0x1b, 0xba, 0x1d, 0xa0 +}; + +const uint8_t kMaskRandom45_39[234] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x3b, 0x48, 0xc7, 0x6d, 0x29, 0xe8 +}; + +const uint8_t kMaskRandom45_4[24] = { + 0xc4, 0xd8, 0x9b, 0x13, 0x45, 0x90, + 0x31, 0x66, 0x2c, 0xc5, 0x8a, 0x58, + 0x4b, 0x29, 0x65, 0x2c, 0x91, 0x68, + 0x2c, 0xa5, 0x94, 0xb2, 0xa2, 0xa8 +}; + +const uint8_t kMaskRandom45_40[240] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x3b, 0x48, 0xc7, 0x6d, 0x29, 0xe8, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0xd9, 0x40, 0x46, 0xe6, 0x4f, 0xd8 +}; + +const uint8_t kMaskRandom45_41[246] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x3b, 0x48, 0xc7, 0x6d, 0x29, 0xe8, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10 +}; + +const uint8_t kMaskRandom45_42[252] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x62, 0x6c, 0x4d, 0x89, 0xf2, 0x10, + 0x8c, 0x11, 0x82, 0x30, 0x12, 0x20, + 0x01, 0x60, 0x2c, 0x05, 0xd0, 0x88, + 0x07, 0x80, 0xf0, 0x1e, 0x0c, 0x18, + 0xa0, 0x94, 0x12, 0x82, 0x01, 0xc8, + 0x18, 0xa3, 0x14, 0x62, 0xc5, 0x08, + 0x91, 0x12, 0x22, 0x44, 0x02, 0x48, + 0x78, 0x0f, 0x01, 0xe0, 0x00, 0x70, + 0x3b, 0x48, 0xc7, 0x6d, 0x29, 0xe8, + 0xac, 0xcc, 0x04, 0x41, 0x97, 0x30 +}; + +const uint8_t kMaskRandom45_43[258] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x9e, 0xce, 0x8b, 0xaa, 0x34, 0x68 +}; + +const uint8_t kMaskRandom45_44[264] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x9e, 0xce, 0x8b, 0xaa, 0x34, 0x68, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0xf8, 0x40, 0xe3, 0x2e, 0x16, 0x00 +}; + +const uint8_t kMaskRandom45_45[270] = { + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x22, 0x88, + 0xa9, 0x15, 0x22, 0xa4, 0x40, 0x68, + 0x04, 0xc0, 0x98, 0x13, 0x12, 0x10, + 0xd0, 0x1a, 0x03, 0x40, 0x05, 0x10, + 0x82, 0x50, 0x4a, 0x09, 0x00, 0x70, + 0x21, 0x24, 0x24, 0x84, 0xdc, 0x00, + 0x0c, 0x21, 0x84, 0x30, 0x84, 0x88, + 0x4a, 0x09, 0x41, 0x28, 0x2b, 0x00, + 0x12, 0xa2, 0x54, 0x4a, 0xd1, 0x40, + 0x9e, 0xce, 0x8b, 0xaa, 0x34, 0x68, + 0x46, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x33, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x99, 0x13, 0x22, 0x64, 0x08, 0x48, + 0x05, 0x80, 0xb0, 0x16, 0x00, 0x38, + 0x80, 0xb0, 0x16, 0x02, 0x86, 0x08, + 0x84, 0x50, 0x8a, 0x11, 0x20, 0x60, + 0x40, 0x68, 0x0d, 0x01, 0xb5, 0x00, + 0x0a, 0x81, 0x50, 0x2a, 0x43, 0x00, + 0x68, 0x0d, 0x01, 0xa0, 0x12, 0x40, + 0x10, 0x22, 0x04, 0x40, 0xc4, 0x80, + 0x30, 0x46, 0x08, 0xc1, 0x60, 0x10, + 0x64, 0x4c, 0x89, 0x19, 0x08, 0x30, + 0x51, 0x4a, 0x28, 0xcc, 0x81, 0x18, + 0xa9, 0x15, 0x22, 0x64, 0x20, 0x28, + 0x04, 0xc0, 0x98, 0x16, 0x10, 0xc0, + 0xd0, 0x1a, 0x02, 0x02, 0xc0, 0x88, + 0x82, 0x50, 0x4a, 0x11, 0x0a, 0x40, + 0x21, 0x24, 0x25, 0x01, 0xcc, 0x00, + 0x0c, 0x21, 0x84, 0x2a, 0x04, 0x48, + 0x4a, 0x09, 0x41, 0xa0, 0x31, 0x00, + 0x12, 0xa2, 0x54, 0x40, 0x92, 0x10, + 0x9e, 0xce, 0x88, 0xc1, 0x45, 0x00, + 0xfb, 0x97, 0x5d, 0x7d, 0x42, 0x20 +}; + +const uint8_t kMaskRandom45_5[30] = { + 0xc6, 0xd8, 0xdb, 0x1b, 0x29, 0xb0, + 0x63, 0x6c, 0x6d, 0x8d, 0xb2, 0x58, + 0x1d, 0xa3, 0xb4, 0x76, 0x87, 0x70, + 0xad, 0x55, 0xaa, 0xb5, 0x54, 0xe0, + 0xb2, 0xb6, 0x56, 0xca, 0xdc, 0x18 +}; + +const uint8_t kMaskRandom45_6[36] = { + 0x64, 0x4c, 0x89, 0x91, 0x28, 0xa0, + 0x51, 0x4a, 0x29, 0x45, 0x62, 0x88, + 0xa8, 0x35, 0x04, 0x32, 0x90, 0xc0, + 0xc4, 0xa0, 0x96, 0x84, 0x89, 0x18, + 0x03, 0x60, 0x6c, 0x4a, 0x84, 0x70, + 0x90, 0xd2, 0x1a, 0x29, 0x17, 0x00 +}; + +const uint8_t kMaskRandom45_7[42] = { + 0xc6, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x13, 0x26, 0x64, 0xcc, 0x90, 0x98, + 0x8d, 0x13, 0xa2, 0x46, 0x48, 0x48, + 0x8b, 0x41, 0x6a, 0x90, 0x81, 0x28, + 0x52, 0xaa, 0x15, 0x42, 0x83, 0x50, + 0xa2, 0xd4, 0x1a, 0x13, 0x16, 0x00, + 0x61, 0xa8, 0x2c, 0x25, 0xc4, 0x30 +}; + +const uint8_t kMaskRandom45_8[48] = { + 0x28, 0x85, 0x38, 0x32, 0x10, 0x30, + 0x21, 0xf4, 0x06, 0x01, 0xc0, 0x18, + 0xe9, 0x1d, 0x02, 0x82, 0x21, 0x20, + 0x17, 0x02, 0xe0, 0x15, 0x00, 0xc8, + 0x83, 0xa0, 0x55, 0x0c, 0x0a, 0x08, + 0x46, 0x18, 0xe8, 0x68, 0x05, 0x40, + 0x50, 0x6a, 0x0d, 0x80, 0x9c, 0x00, + 0x1c, 0x23, 0x84, 0x50, 0xe2, 0x80 +}; + +const uint8_t kMaskRandom45_9[54] = { + 0x44, 0x48, 0xc9, 0x19, 0x29, 0xb0, + 0x28, 0x2d, 0x0d, 0x89, 0xf2, 0x10, + 0x25, 0x14, 0xa2, 0x30, 0x12, 0x20, + 0x59, 0x0a, 0x20, 0x05, 0xd0, 0x88, + 0x03, 0xa0, 0x34, 0x1e, 0x0c, 0x18, + 0xc0, 0xd0, 0x1a, 0x82, 0x01, 0xc8, + 0xa2, 0x30, 0x44, 0x62, 0xc5, 0x08, + 0x14, 0x82, 0xd2, 0x44, 0x02, 0x48, + 0x9a, 0x03, 0x81, 0xe0, 0x00, 0x70 +}; + +const uint8_t kMaskRandom46_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc +}; + +const uint8_t kMaskRandom46_10[60] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0 +}; + +const uint8_t kMaskRandom46_11[66] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08 +}; + +const uint8_t kMaskRandom46_12[72] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x86, 0x8a, 0x6d, 0x0d, 0x14, 0xd8, + 0x23, 0x2c, 0x84, 0x46, 0x59, 0x08, + 0x16, 0x21, 0x98, 0x2c, 0x43, 0x30, + 0x4c, 0x30, 0x54, 0x98, 0x60, 0xa8, + 0x41, 0xc1, 0x26, 0x83, 0x82, 0x4c, + 0x19, 0x56, 0xe4, 0x32, 0xad, 0xc8 +}; + +const uint8_t kMaskRandom46_13[78] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18 +}; + +const uint8_t kMaskRandom46_14[84] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x9c, 0x3f, 0xb3, 0x38, 0x7f, 0x64 +}; + +const uint8_t kMaskRandom46_15[90] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40 +}; + +const uint8_t kMaskRandom46_16[96] = { + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0xfa, 0xd9, 0xf5, 0xf5, 0xb3, 0xe8 +}; + +const uint8_t kMaskRandom46_17[102] = { + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38 +}; + +const uint8_t kMaskRandom46_18[108] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x82, 0x32, 0x57, 0x04, 0x64, 0xac +}; + +const uint8_t kMaskRandom46_19[114] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0 +}; + +const uint8_t kMaskRandom46_2[12] = { + 0xec, 0xdd, 0x99, 0xd9, 0xbb, 0x30, + 0x9b, 0xb2, 0x77, 0x37, 0x64, 0xec +}; + +const uint8_t kMaskRandom46_20[120] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0xdb, 0x4a, 0x7b, 0xb6, 0x94, 0xf4 +}; + +const uint8_t kMaskRandom46_21[126] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08 +}; + +const uint8_t kMaskRandom46_22[132] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0xea, 0x8d, 0x1b, 0xd5, 0x1a, 0x34 +}; + +const uint8_t kMaskRandom46_23[138] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x46, 0x42, 0x0c, 0x8c, 0x84, 0x18, + 0x33, 0x20, 0x46, 0x66, 0x40, 0x8c, + 0x99, 0x08, 0x0b, 0x32, 0x10, 0x14, + 0x05, 0x84, 0x30, 0x0b, 0x08, 0x60, + 0x80, 0xb0, 0x23, 0x01, 0x60, 0x44, + 0x84, 0x42, 0x91, 0x08, 0x85, 0x20, + 0x40, 0x73, 0x00, 0x80, 0xe6, 0x00, + 0x0a, 0x81, 0x12, 0x15, 0x02, 0x24, + 0x68, 0x0c, 0x40, 0xd0, 0x18, 0x80, + 0x10, 0x24, 0x84, 0x20, 0x49, 0x08, + 0x30, 0x51, 0x40, 0x60, 0xa2, 0x80, + 0x5f, 0x50, 0x88, 0xbe, 0xa1, 0x10 +}; + +const uint8_t kMaskRandom46_24[144] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x86, 0x8a, 0x6d, 0x0d, 0x14, 0xd8, + 0x23, 0x2c, 0x84, 0x46, 0x59, 0x08, + 0x16, 0x21, 0x98, 0x2c, 0x43, 0x30, + 0x4c, 0x30, 0x54, 0x98, 0x60, 0xa8, + 0x41, 0xc1, 0x26, 0x83, 0x82, 0x4c, + 0x19, 0x56, 0xe4, 0x32, 0xad, 0xc8, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x18, 0x8b, 0x03, 0xb4, 0x3b, 0x10 +}; + +const uint8_t kMaskRandom46_25[150] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x86, 0x8a, 0x6d, 0x0d, 0x14, 0xd8, + 0x23, 0x2c, 0x84, 0x46, 0x59, 0x08, + 0x16, 0x21, 0x98, 0x2c, 0x43, 0x30, + 0x4c, 0x30, 0x54, 0x98, 0x60, 0xa8, + 0x41, 0xc1, 0x26, 0x83, 0x82, 0x4c, + 0x19, 0x56, 0xe4, 0x32, 0xad, 0xc8, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18 +}; + +const uint8_t kMaskRandom46_26[156] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x86, 0x8a, 0x6d, 0x0d, 0x14, 0xd8, + 0x23, 0x2c, 0x84, 0x46, 0x59, 0x08, + 0x16, 0x21, 0x98, 0x2c, 0x43, 0x30, + 0x4c, 0x30, 0x54, 0x98, 0x60, 0xa8, + 0x41, 0xc1, 0x26, 0x83, 0x82, 0x4c, + 0x19, 0x56, 0xe4, 0x32, 0xad, 0xc8, + 0x2d, 0x6d, 0xd2, 0x57, 0xd6, 0x2c +}; + +const uint8_t kMaskRandom46_27[162] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x9c, 0x3f, 0xb3, 0x38, 0x7f, 0x64 +}; + +const uint8_t kMaskRandom46_28[168] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x9c, 0x3f, 0xb3, 0x38, 0x7f, 0x64, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0xfa, 0x52, 0xf9, 0x72, 0xd9, 0x68 +}; + +const uint8_t kMaskRandom46_29[174] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x9c, 0x3f, 0xb3, 0x38, 0x7f, 0x64, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40 +}; + +const uint8_t kMaskRandom46_3[18] = { + 0xca, 0xd3, 0x65, 0x95, 0xa6, 0xc8, + 0xf1, 0x49, 0x3b, 0xe2, 0x92, 0x74, + 0x76, 0x27, 0xd0, 0xec, 0x4f, 0xa0 +}; + +const uint8_t kMaskRandom46_30[180] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80, + 0x9c, 0x3f, 0xb3, 0x38, 0x7f, 0x64, + 0x99, 0xf6, 0x0a, 0xdd, 0x16, 0xb0 +}; + +const uint8_t kMaskRandom46_31[186] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0xfa, 0xd9, 0xf5, 0xf5, 0xb3, 0xe8 +}; + +const uint8_t kMaskRandom46_32[192] = { + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0xfa, 0xd9, 0xf5, 0xf5, 0xb3, 0xe8, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x69, 0xcd, 0xeb, 0x51, 0xc9, 0xa8 +}; + +const uint8_t kMaskRandom46_33[198] = { + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0xfa, 0xd9, 0xf5, 0xf5, 0xb3, 0xe8, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38 +}; + +const uint8_t kMaskRandom46_34[204] = { + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18, + 0xfa, 0xd9, 0xf5, 0xf5, 0xb3, 0xe8, + 0x60, 0xf0, 0x13, 0xf0, 0x4d, 0xe0 +}; + +const uint8_t kMaskRandom46_35[210] = { + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x82, 0x32, 0x57, 0x04, 0x64, 0xac +}; + +const uint8_t kMaskRandom46_36[216] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x82, 0x32, 0x57, 0x04, 0x64, 0xac, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x6c, 0x3a, 0x45, 0x70, 0xd7, 0x00 +}; + +const uint8_t kMaskRandom46_37[222] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x82, 0x32, 0x57, 0x04, 0x64, 0xac, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0 +}; + +const uint8_t kMaskRandom46_38[228] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40, + 0x82, 0x32, 0x57, 0x04, 0x64, 0xac, + 0x72, 0x2b, 0xa5, 0xd4, 0xb9, 0x30 +}; + +const uint8_t kMaskRandom46_39[234] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0xdb, 0x4a, 0x7b, 0xb6, 0x94, 0xf4 +}; + +const uint8_t kMaskRandom46_4[24] = { + 0xc4, 0xd1, 0x65, 0x89, 0xa2, 0xc8, + 0x31, 0x62, 0x96, 0x62, 0xc5, 0x2c, + 0x4b, 0x24, 0x5a, 0x96, 0x48, 0xb4, + 0x2c, 0xa8, 0xaa, 0x59, 0x51, 0x54 +}; + +const uint8_t kMaskRandom46_40[240] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0xdb, 0x4a, 0x7b, 0xb6, 0x94, 0xf4, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x7c, 0xc8, 0x93, 0x63, 0x3c, 0x80 +}; + +const uint8_t kMaskRandom46_41[246] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0xdb, 0x4a, 0x7b, 0xb6, 0x94, 0xf4, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08 +}; + +const uint8_t kMaskRandom46_42[252] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38, + 0xdb, 0x4a, 0x7b, 0xb6, 0x94, 0xf4, + 0xfc, 0x6e, 0x89, 0x54, 0x4f, 0x00 +}; + +const uint8_t kMaskRandom46_43[258] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0xea, 0x8d, 0x1b, 0xd5, 0x1a, 0x34 +}; + +const uint8_t kMaskRandom46_44[264] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0xea, 0x8d, 0x1b, 0xd5, 0x1a, 0x34, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x1a, 0x8a, 0x00, 0x1c, 0x89, 0x54 +}; + +const uint8_t kMaskRandom46_45[270] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0xea, 0x8d, 0x1b, 0xd5, 0x1a, 0x34, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x46, 0x42, 0x0c, 0x8c, 0x84, 0x18, + 0x33, 0x20, 0x46, 0x66, 0x40, 0x8c, + 0x99, 0x08, 0x0b, 0x32, 0x10, 0x14, + 0x05, 0x84, 0x30, 0x0b, 0x08, 0x60, + 0x80, 0xb0, 0x23, 0x01, 0x60, 0x44, + 0x84, 0x42, 0x91, 0x08, 0x85, 0x20, + 0x40, 0x73, 0x00, 0x80, 0xe6, 0x00, + 0x0a, 0x81, 0x12, 0x15, 0x02, 0x24, + 0x68, 0x0c, 0x40, 0xd0, 0x18, 0x80, + 0x10, 0x24, 0x84, 0x20, 0x49, 0x08, + 0x30, 0x51, 0x40, 0x60, 0xa2, 0x80, + 0x5f, 0x50, 0x88, 0xbe, 0xa1, 0x10 +}; + +const uint8_t kMaskRandom46_46[276] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x46, 0x42, 0x0c, 0x8c, 0x84, 0x18, + 0x33, 0x20, 0x46, 0x66, 0x40, 0x8c, + 0x99, 0x08, 0x0b, 0x32, 0x10, 0x14, + 0x05, 0x84, 0x30, 0x0b, 0x08, 0x60, + 0x80, 0xb0, 0x23, 0x01, 0x60, 0x44, + 0x84, 0x42, 0x91, 0x08, 0x85, 0x20, + 0x40, 0x73, 0x00, 0x80, 0xe6, 0x00, + 0x0a, 0x81, 0x12, 0x15, 0x02, 0x24, + 0x68, 0x0c, 0x40, 0xd0, 0x18, 0x80, + 0x10, 0x24, 0x84, 0x20, 0x49, 0x08, + 0x30, 0x51, 0x40, 0x60, 0xa2, 0x80, + 0x5f, 0x50, 0x88, 0xbe, 0xa1, 0x10, + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x99, 0x02, 0x13, 0x32, 0x04, 0x24, + 0x05, 0x80, 0x0e, 0x0b, 0x00, 0x1c, + 0x80, 0xa1, 0x83, 0x01, 0x43, 0x04, + 0x84, 0x48, 0x19, 0x08, 0x90, 0x30, + 0x40, 0x6d, 0x40, 0x80, 0xda, 0x80, + 0x0a, 0x90, 0xc0, 0x15, 0x21, 0x80, + 0x68, 0x04, 0x90, 0xd0, 0x09, 0x20, + 0x10, 0x31, 0x20, 0x20, 0x62, 0x40, + 0x30, 0x58, 0x04, 0x60, 0xb0, 0x08, + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x48, 0xa2, 0xa2, 0x91, 0x44, + 0xa9, 0x10, 0x1b, 0x52, 0x20, 0x34, + 0x04, 0xc4, 0x84, 0x09, 0x89, 0x08, + 0xd0, 0x01, 0x45, 0xa0, 0x02, 0x88, + 0x82, 0x40, 0x1d, 0x04, 0x80, 0x38, + 0x21, 0x37, 0x00, 0x42, 0x6e, 0x00, + 0x0c, 0x21, 0x22, 0x18, 0x42, 0x44, + 0x4a, 0x0a, 0xc0, 0x94, 0x15, 0x80, + 0x12, 0xb4, 0x50, 0x25, 0x68, 0xa0, + 0xea, 0x8d, 0x1b, 0xd5, 0x1a, 0x34, + 0xd5, 0xdf, 0x59, 0xb9, 0xba, 0x10 +}; + +const uint8_t kMaskRandom46_5[30] = { + 0xc6, 0xca, 0x6d, 0x8d, 0x94, 0xd8, + 0x63, 0x6c, 0x96, 0xc6, 0xd9, 0x2c, + 0x1d, 0xa1, 0xdc, 0x3b, 0x43, 0xb8, + 0xad, 0x55, 0x39, 0x5a, 0xaa, 0x70, + 0xb2, 0xb7, 0x07, 0x65, 0x6e, 0x0c +}; + +const uint8_t kMaskRandom46_6[36] = { + 0x64, 0x4a, 0x28, 0xc8, 0x94, 0x50, + 0x51, 0x58, 0xa2, 0xa2, 0xb1, 0x44, + 0x0c, 0xa4, 0x30, 0x19, 0x48, 0x60, + 0xa1, 0x22, 0x47, 0x42, 0x44, 0x8c, + 0x12, 0xa1, 0x1c, 0x25, 0x42, 0x38, + 0x8a, 0x45, 0xc1, 0x14, 0x8b, 0x80 +}; + +const uint8_t kMaskRandom46_7[42] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x33, 0x24, 0x26, 0x66, 0x48, 0x4c, + 0x91, 0x92, 0x13, 0x23, 0x24, 0x24, + 0xa4, 0x20, 0x4b, 0x48, 0x40, 0x94, + 0x50, 0xa0, 0xd4, 0xa1, 0x41, 0xa8, + 0x84, 0xc5, 0x81, 0x09, 0x8b, 0x00, + 0x09, 0x71, 0x0c, 0x12, 0xe2, 0x18 +}; + +const uint8_t kMaskRandom46_8[48] = { + 0x0c, 0x84, 0x0c, 0x19, 0x08, 0x18, + 0x80, 0x70, 0x07, 0x00, 0xe0, 0x0c, + 0xa0, 0x88, 0x49, 0x41, 0x10, 0x90, + 0x05, 0x40, 0x32, 0x0a, 0x80, 0x64, + 0x43, 0x02, 0x82, 0x86, 0x05, 0x04, + 0x1a, 0x01, 0x50, 0x34, 0x02, 0xa0, + 0x60, 0x27, 0x00, 0xc0, 0x4e, 0x00, + 0x14, 0x38, 0xa0, 0x28, 0x71, 0x40 +}; + +const uint8_t kMaskRandom46_9[54] = { + 0x46, 0x4a, 0x6c, 0x8c, 0x94, 0xd8, + 0x62, 0x7c, 0x84, 0xc4, 0xf9, 0x08, + 0x8c, 0x04, 0x89, 0x18, 0x09, 0x10, + 0x01, 0x74, 0x22, 0x02, 0xe8, 0x44, + 0x07, 0x83, 0x06, 0x0f, 0x06, 0x0c, + 0xa0, 0x80, 0x73, 0x41, 0x00, 0xe4, + 0x18, 0xb1, 0x42, 0x31, 0x62, 0x84, + 0x91, 0x00, 0x93, 0x22, 0x01, 0x24, + 0x78, 0x00, 0x1c, 0xf0, 0x00, 0x38 +}; + +const uint8_t kMaskRandom47_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe +}; + +const uint8_t kMaskRandom47_10[60] = { + 0x64, 0x4a, 0x28, 0x22, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x68, 0xa6, + 0xa9, 0x10, 0x1a, 0x00, 0x90, 0x0a, + 0x04, 0xc4, 0x84, 0x21, 0x06, 0x12, + 0xd0, 0x01, 0x44, 0x94, 0x29, 0x42, + 0x82, 0x40, 0x1c, 0x81, 0x48, 0x14, + 0x21, 0x37, 0x01, 0x40, 0xd4, 0x04, + 0x0c, 0x21, 0x23, 0x11, 0x01, 0x18, + 0x4a, 0x0a, 0xc1, 0x0c, 0x10, 0xc0, + 0x12, 0xb4, 0x50, 0xa8, 0x1a, 0x80 +}; + +const uint8_t kMaskRandom47_11[66] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x68, + 0x33, 0x24, 0x27, 0x40, 0x64, 0x22, + 0x99, 0x02, 0x12, 0x2a, 0x22, 0x82, + 0x05, 0x80, 0x0e, 0x06, 0xa0, 0x2a, + 0x80, 0xa1, 0x83, 0x19, 0x11, 0x90, + 0x84, 0x48, 0x18, 0x51, 0x05, 0x10, + 0x40, 0x6d, 0x40, 0x10, 0x91, 0x08, + 0x0a, 0x90, 0xc1, 0x32, 0x03, 0x20, + 0x68, 0x04, 0x90, 0x45, 0x24, 0x52, + 0x10, 0x31, 0x20, 0x8c, 0x08, 0xc0, + 0x30, 0x58, 0x05, 0x18, 0x58, 0x04 +}; + +const uint8_t kMaskRandom47_12[72] = { + 0x64, 0x4a, 0x28, 0x20, 0xc2, 0x0c, + 0x51, 0x58, 0xa2, 0x04, 0x60, 0x46, + 0x0c, 0xa4, 0x30, 0x80, 0xa8, 0x0a, + 0xa1, 0x22, 0x46, 0x43, 0x04, 0x30, + 0x12, 0xa1, 0x1d, 0x02, 0x30, 0x22, + 0x8a, 0x45, 0xc0, 0x29, 0x02, 0x90, + 0x86, 0x8a, 0x6d, 0x30, 0x13, 0x00, + 0x23, 0x2c, 0x84, 0x11, 0x21, 0x12, + 0x16, 0x21, 0x98, 0xc4, 0x0c, 0x40, + 0x4c, 0x30, 0x54, 0x48, 0x44, 0x84, + 0x41, 0xc1, 0x27, 0x14, 0x11, 0x40, + 0x19, 0x56, 0xe5, 0x08, 0x90, 0x88 +}; + +const uint8_t kMaskRandom47_13[78] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c +}; + +const uint8_t kMaskRandom47_14[84] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x9c, 0x3f, 0xb3, 0xe5, 0xad, 0x1c +}; + +const uint8_t kMaskRandom47_15[90] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0 +}; + +const uint8_t kMaskRandom47_16[96] = { + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0xfa, 0xd9, 0xf5, 0xfe, 0xdc, 0x14 +}; + +const uint8_t kMaskRandom47_17[102] = { + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c +}; + +const uint8_t kMaskRandom47_18[108] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x82, 0x32, 0x56, 0x68, 0xa1, 0x5c +}; + +const uint8_t kMaskRandom47_19[114] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50 +}; + +const uint8_t kMaskRandom47_2[12] = { + 0xec, 0xdd, 0x99, 0xd9, 0x9d, 0x98, + 0x9b, 0xb2, 0x77, 0x27, 0x72, 0x76 +}; + +const uint8_t kMaskRandom47_20[120] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0xdb, 0x4a, 0x7b, 0x31, 0x45, 0x2a +}; + +const uint8_t kMaskRandom47_21[126] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04 +}; + +const uint8_t kMaskRandom47_22[132] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0xea, 0x8d, 0x1a, 0x35, 0x55, 0xdc +}; + +const uint8_t kMaskRandom47_23[138] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x46, 0x42, 0x0c, 0x20, 0xc2, 0x0c, + 0x33, 0x20, 0x46, 0x04, 0x60, 0x46, + 0x99, 0x08, 0x0a, 0x80, 0xa8, 0x0a, + 0x05, 0x84, 0x30, 0x43, 0x04, 0x30, + 0x80, 0xb0, 0x23, 0x02, 0x30, 0x22, + 0x84, 0x42, 0x90, 0x29, 0x02, 0x90, + 0x40, 0x73, 0x01, 0x30, 0x13, 0x00, + 0x0a, 0x81, 0x12, 0x11, 0x21, 0x12, + 0x68, 0x0c, 0x40, 0xc4, 0x0c, 0x40, + 0x10, 0x24, 0x84, 0x48, 0x44, 0x84, + 0x30, 0x51, 0x41, 0x14, 0x11, 0x40, + 0x5f, 0x50, 0x89, 0x08, 0x90, 0x88 +}; + +const uint8_t kMaskRandom47_24[144] = { + 0x64, 0x4a, 0x28, 0x20, 0xc2, 0x0c, + 0x51, 0x58, 0xa2, 0x04, 0x60, 0x46, + 0x0c, 0xa4, 0x30, 0x80, 0xa8, 0x0a, + 0xa1, 0x22, 0x46, 0x43, 0x04, 0x30, + 0x12, 0xa1, 0x1d, 0x02, 0x30, 0x22, + 0x8a, 0x45, 0xc0, 0x29, 0x02, 0x90, + 0x86, 0x8a, 0x6d, 0x30, 0x13, 0x00, + 0x23, 0x2c, 0x84, 0x11, 0x21, 0x12, + 0x16, 0x21, 0x98, 0xc4, 0x0c, 0x40, + 0x4c, 0x30, 0x54, 0x48, 0x44, 0x84, + 0x41, 0xc1, 0x27, 0x14, 0x11, 0x40, + 0x19, 0x56, 0xe5, 0x08, 0x90, 0x88, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x68, + 0x33, 0x24, 0x27, 0x40, 0x64, 0x22, + 0x99, 0x02, 0x12, 0x2a, 0x22, 0x82, + 0x05, 0x80, 0x0e, 0x06, 0xa0, 0x2a, + 0x80, 0xa1, 0x83, 0x19, 0x11, 0x90, + 0x84, 0x48, 0x18, 0x51, 0x05, 0x10, + 0x40, 0x6d, 0x40, 0x10, 0x91, 0x08, + 0x0a, 0x90, 0xc1, 0x32, 0x03, 0x20, + 0x68, 0x04, 0x90, 0x45, 0x24, 0x52, + 0x10, 0x31, 0x20, 0x8c, 0x08, 0xc0, + 0x30, 0x58, 0x05, 0x18, 0x58, 0x04, + 0x27, 0x41, 0x35, 0x57, 0x7e, 0x6a +}; + +const uint8_t kMaskRandom47_25[150] = { + 0x64, 0x4a, 0x28, 0x20, 0xc2, 0x0c, + 0x51, 0x58, 0xa2, 0x04, 0x60, 0x46, + 0x0c, 0xa4, 0x30, 0x80, 0xa8, 0x0a, + 0xa1, 0x22, 0x46, 0x43, 0x04, 0x30, + 0x12, 0xa1, 0x1d, 0x02, 0x30, 0x22, + 0x8a, 0x45, 0xc0, 0x29, 0x02, 0x90, + 0x86, 0x8a, 0x6d, 0x30, 0x13, 0x00, + 0x23, 0x2c, 0x84, 0x11, 0x21, 0x12, + 0x16, 0x21, 0x98, 0xc4, 0x0c, 0x40, + 0x4c, 0x30, 0x54, 0x48, 0x44, 0x84, + 0x41, 0xc1, 0x27, 0x14, 0x11, 0x40, + 0x19, 0x56, 0xe5, 0x08, 0x90, 0x88, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c +}; + +const uint8_t kMaskRandom47_26[156] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x64, 0x4a, 0x28, 0x20, 0xc2, 0x0c, + 0x51, 0x58, 0xa2, 0x04, 0x60, 0x46, + 0x0c, 0xa4, 0x30, 0x80, 0xa8, 0x0a, + 0xa1, 0x22, 0x46, 0x43, 0x04, 0x30, + 0x12, 0xa1, 0x1d, 0x02, 0x30, 0x22, + 0x8a, 0x45, 0xc0, 0x29, 0x02, 0x90, + 0x86, 0x8a, 0x6d, 0x30, 0x13, 0x00, + 0x23, 0x2c, 0x84, 0x11, 0x21, 0x12, + 0x16, 0x21, 0x98, 0xc4, 0x0c, 0x40, + 0x4c, 0x30, 0x54, 0x48, 0x44, 0x84, + 0x41, 0xc1, 0x27, 0x14, 0x11, 0x40, + 0x19, 0x56, 0xe5, 0x08, 0x90, 0x88, + 0x6c, 0xea, 0xc4, 0x42, 0x20, 0x9e +}; + +const uint8_t kMaskRandom47_27[162] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x9c, 0x3f, 0xb3, 0xe5, 0xad, 0x1c +}; + +const uint8_t kMaskRandom47_28[168] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x9c, 0x3f, 0xb3, 0xe5, 0xad, 0x1c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x86, 0x1e, 0xa6, 0xaf, 0x3d, 0x04 +}; + +const uint8_t kMaskRandom47_29[174] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x9c, 0x3f, 0xb3, 0xe5, 0xad, 0x1c, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0 +}; + +const uint8_t kMaskRandom47_3[18] = { + 0xca, 0xd3, 0x65, 0x36, 0x53, 0x64, + 0xf1, 0x49, 0x3a, 0x93, 0xa9, 0x3a, + 0x76, 0x27, 0xd0, 0x7d, 0x07, 0xd0 +}; + +const uint8_t kMaskRandom47_30[180] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x58, 0xa3, 0x8a, 0x38, 0xa2, + 0x0c, 0xa4, 0x30, 0x43, 0x04, 0x30, + 0xa1, 0x22, 0x46, 0x24, 0x62, 0x46, + 0x12, 0xa1, 0x1c, 0x11, 0xc1, 0x1c, + 0x8a, 0x45, 0xc0, 0x5c, 0x05, 0xc0, + 0x9c, 0x3f, 0xb3, 0xe5, 0xad, 0x1c, + 0x97, 0x43, 0x63, 0xc6, 0x09, 0x9c +}; + +const uint8_t kMaskRandom47_31[186] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0xfa, 0xd9, 0xf5, 0xfe, 0xdc, 0x14 +}; + +const uint8_t kMaskRandom47_32[192] = { + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0xfa, 0xd9, 0xf5, 0xfe, 0xdc, 0x14, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0xe5, 0x50, 0x45, 0x63, 0xc2, 0xf4 +}; + +const uint8_t kMaskRandom47_33[198] = { + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0xfa, 0xd9, 0xf5, 0xfe, 0xdc, 0x14, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c +}; + +const uint8_t kMaskRandom47_34[204] = { + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x91, 0x92, 0x13, 0x21, 0x32, 0x12, + 0xa4, 0x20, 0x4a, 0x04, 0xa0, 0x4a, + 0x50, 0xa0, 0xd4, 0x0d, 0x40, 0xd4, + 0x84, 0xc5, 0x80, 0x58, 0x05, 0x80, + 0x09, 0x71, 0x0d, 0x10, 0xd1, 0x0c, + 0xfa, 0xd9, 0xf5, 0xfe, 0xdc, 0x14, + 0xef, 0xbb, 0xa6, 0x23, 0x5c, 0xbe +}; + +const uint8_t kMaskRandom47_35[210] = { + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x82, 0x32, 0x56, 0x68, 0xa1, 0x5c +}; + +const uint8_t kMaskRandom47_36[216] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x82, 0x32, 0x56, 0x68, 0xa1, 0x5c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x0e, 0xd7, 0x38, 0x20, 0x87, 0x66 +}; + +const uint8_t kMaskRandom47_37[222] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x82, 0x32, 0x56, 0x68, 0xa1, 0x5c, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50 +}; + +const uint8_t kMaskRandom47_38[228] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x0c, 0x84, 0x0c, 0x40, 0xc4, 0x0c, + 0x80, 0x70, 0x07, 0x00, 0x70, 0x06, + 0xa0, 0x88, 0x48, 0x84, 0x88, 0x48, + 0x05, 0x40, 0x32, 0x03, 0x20, 0x32, + 0x43, 0x02, 0x82, 0x28, 0x22, 0x82, + 0x1a, 0x01, 0x50, 0x15, 0x01, 0x50, + 0x60, 0x27, 0x00, 0x70, 0x07, 0x00, + 0x14, 0x38, 0xa1, 0x8a, 0x18, 0xa0, + 0x82, 0x32, 0x56, 0x68, 0xa1, 0x5c, + 0x7b, 0x47, 0xa5, 0xde, 0x9a, 0xd4 +}; + +const uint8_t kMaskRandom47_39[234] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0xdb, 0x4a, 0x7b, 0x31, 0x45, 0x2a +}; + +const uint8_t kMaskRandom47_4[24] = { + 0xc4, 0xd1, 0x65, 0x16, 0x51, 0x64, + 0x31, 0x62, 0x96, 0x29, 0x62, 0x96, + 0x4b, 0x24, 0x5a, 0x45, 0xa4, 0x5a, + 0x2c, 0xa8, 0xaa, 0x8a, 0xa8, 0xaa +}; + +const uint8_t kMaskRandom47_40[240] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0xdb, 0x4a, 0x7b, 0x31, 0x45, 0x2a, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0xc4, 0xae, 0x5e, 0x33, 0xf5, 0x1a +}; + +const uint8_t kMaskRandom47_41[246] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0xdb, 0x4a, 0x7b, 0x31, 0x45, 0x2a, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04 +}; + +const uint8_t kMaskRandom47_42[252] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x85, 0xc8, 0x5c, 0x84, + 0x8c, 0x04, 0x88, 0x48, 0x84, 0x88, + 0x01, 0x74, 0x23, 0x42, 0x34, 0x22, + 0x07, 0x83, 0x06, 0x30, 0x63, 0x06, + 0xa0, 0x80, 0x72, 0x07, 0x20, 0x72, + 0x18, 0xb1, 0x43, 0x14, 0x31, 0x42, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x01, 0xc0, 0x1c, + 0xdb, 0x4a, 0x7b, 0x31, 0x45, 0x2a, + 0x3c, 0xb0, 0x36, 0x3b, 0x14, 0xa2 +}; + +const uint8_t kMaskRandom47_43[258] = { + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0xea, 0x8d, 0x1a, 0x35, 0x55, 0xdc +}; + +const uint8_t kMaskRandom47_44[264] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0xea, 0x8d, 0x1a, 0x35, 0x55, 0xdc, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0xd4, 0x8a, 0xd4, 0xd3, 0x3f, 0xe6 +}; + +const uint8_t kMaskRandom47_45[270] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0xea, 0x8d, 0x1a, 0x35, 0x55, 0xdc, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x46, 0x42, 0x0c, 0x20, 0xc2, 0x0c, + 0x33, 0x20, 0x46, 0x04, 0x60, 0x46, + 0x99, 0x08, 0x0a, 0x80, 0xa8, 0x0a, + 0x05, 0x84, 0x30, 0x43, 0x04, 0x30, + 0x80, 0xb0, 0x23, 0x02, 0x30, 0x22, + 0x84, 0x42, 0x90, 0x29, 0x02, 0x90, + 0x40, 0x73, 0x01, 0x30, 0x13, 0x00, + 0x0a, 0x81, 0x12, 0x11, 0x21, 0x12, + 0x68, 0x0c, 0x40, 0xc4, 0x0c, 0x40, + 0x10, 0x24, 0x84, 0x48, 0x44, 0x84, + 0x30, 0x51, 0x41, 0x14, 0x11, 0x40, + 0x5f, 0x50, 0x89, 0x08, 0x90, 0x88 +}; + +const uint8_t kMaskRandom47_46[276] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x46, 0x42, 0x0c, 0x20, 0xc2, 0x0c, + 0x33, 0x20, 0x46, 0x04, 0x60, 0x46, + 0x99, 0x08, 0x0a, 0x80, 0xa8, 0x0a, + 0x05, 0x84, 0x30, 0x43, 0x04, 0x30, + 0x80, 0xb0, 0x23, 0x02, 0x30, 0x22, + 0x84, 0x42, 0x90, 0x29, 0x02, 0x90, + 0x40, 0x73, 0x01, 0x30, 0x13, 0x00, + 0x0a, 0x81, 0x12, 0x11, 0x21, 0x12, + 0x68, 0x0c, 0x40, 0xc4, 0x0c, 0x40, + 0x10, 0x24, 0x84, 0x48, 0x44, 0x84, + 0x30, 0x51, 0x41, 0x14, 0x11, 0x40, + 0x5f, 0x50, 0x89, 0x08, 0x90, 0x88, + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x64, 0x4a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x48, 0xa2, 0x8a, 0x28, 0xa2, + 0xa9, 0x10, 0x1b, 0x01, 0xb0, 0x1a, + 0x04, 0xc4, 0x84, 0x48, 0x44, 0x84, + 0xd0, 0x01, 0x44, 0x14, 0x41, 0x44, + 0x82, 0x40, 0x1c, 0x01, 0xc0, 0x1c, + 0x21, 0x37, 0x01, 0x70, 0x17, 0x00, + 0x0c, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x4a, 0x0a, 0xc0, 0xac, 0x0a, 0xc0, + 0x12, 0xb4, 0x51, 0x45, 0x14, 0x50, + 0xea, 0x8d, 0x1a, 0x35, 0x55, 0xdc, + 0x37, 0x9d, 0xcf, 0xe0, 0xe4, 0x20 +}; + +const uint8_t kMaskRandom47_47[282] = { + 0x46, 0x4a, 0x6c, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x42, 0x64, 0x26, + 0x99, 0x02, 0x12, 0x21, 0x22, 0x12, + 0x05, 0x80, 0x0e, 0x00, 0xe0, 0x0e, + 0x80, 0xa1, 0x82, 0x18, 0x21, 0x82, + 0x84, 0x48, 0x18, 0x81, 0x88, 0x18, + 0x40, 0x6d, 0x40, 0xd4, 0x0d, 0x40, + 0x0a, 0x90, 0xc1, 0x0c, 0x10, 0xc0, + 0x68, 0x04, 0x90, 0x49, 0x04, 0x90, + 0x10, 0x31, 0x21, 0x12, 0x11, 0x20, + 0x30, 0x58, 0x05, 0x80, 0x58, 0x04, + 0x46, 0x42, 0x0c, 0x20, 0xc2, 0x0c, + 0x33, 0x20, 0x46, 0x04, 0x60, 0x46, + 0x99, 0x08, 0x0a, 0x80, 0xa8, 0x0a, + 0x05, 0x84, 0x30, 0x43, 0x04, 0x30, + 0x80, 0xb0, 0x23, 0x02, 0x30, 0x22, + 0x84, 0x42, 0x90, 0x29, 0x02, 0x90, + 0x40, 0x73, 0x01, 0x30, 0x13, 0x00, + 0x0a, 0x81, 0x12, 0x11, 0x21, 0x12, + 0x68, 0x0c, 0x40, 0xc4, 0x0c, 0x40, + 0x10, 0x24, 0x84, 0x48, 0x44, 0x84, + 0x30, 0x51, 0x41, 0x14, 0x11, 0x40, + 0x5f, 0x50, 0x89, 0x08, 0x90, 0x88, + 0x46, 0x4a, 0x6c, 0x20, 0xc2, 0x0c, + 0x33, 0x24, 0x26, 0x04, 0x60, 0x46, + 0x99, 0x02, 0x12, 0x80, 0xa8, 0x0a, + 0x05, 0x80, 0x0e, 0x43, 0x04, 0x30, + 0x80, 0xa1, 0x83, 0x02, 0x30, 0x22, + 0x84, 0x48, 0x18, 0x29, 0x02, 0x90, + 0x40, 0x6d, 0x41, 0x30, 0x13, 0x00, + 0x0a, 0x90, 0xc0, 0x11, 0x21, 0x12, + 0x68, 0x04, 0x90, 0xc4, 0x0c, 0x40, + 0x10, 0x31, 0x20, 0x48, 0x44, 0x84, + 0x30, 0x58, 0x05, 0x14, 0x11, 0x40, + 0x46, 0x42, 0x0d, 0x08, 0x90, 0x88, + 0x33, 0x20, 0x46, 0xa6, 0xca, 0x6c, + 0x99, 0x08, 0x0a, 0x42, 0x64, 0x26, + 0x05, 0x84, 0x30, 0x21, 0x22, 0x12, + 0x80, 0xb0, 0x22, 0x00, 0xe0, 0x0e, + 0x84, 0x42, 0x90, 0x18, 0x21, 0x82, + 0x40, 0x73, 0x00, 0x81, 0x88, 0x18, + 0x0a, 0x81, 0x12, 0xd4, 0x0d, 0x40, + 0x68, 0x0c, 0x41, 0x0c, 0x10, 0xc0, + 0x10, 0x24, 0x84, 0x49, 0x04, 0x90, + 0x30, 0x51, 0x41, 0x12, 0x11, 0x20, + 0x5f, 0x50, 0x89, 0x80, 0x58, 0x04, + 0x1f, 0x2f, 0x63, 0x10, 0x64, 0xb2 +}; + +const uint8_t kMaskRandom47_5[30] = { + 0xc6, 0xca, 0x6c, 0xa6, 0xca, 0x6c, + 0x63, 0x6c, 0x96, 0xc9, 0x6c, 0x96, + 0x1d, 0xa1, 0xdc, 0x1d, 0xc1, 0xdc, + 0xad, 0x55, 0x39, 0x53, 0x95, 0x38, + 0xb2, 0xb7, 0x07, 0x70, 0x77, 0x06 +}; + +const uint8_t kMaskRandom47_6[36] = { + 0x64, 0x4a, 0x29, 0xa2, 0x9a, 0x28, + 0x51, 0x58, 0xa2, 0x8a, 0x68, 0xa6, + 0x0c, 0xa4, 0x30, 0x45, 0xa4, 0x5a, + 0xa1, 0x22, 0x46, 0x2d, 0x82, 0xd8, + 0x12, 0xa1, 0x1c, 0x17, 0x41, 0x74, + 0x8a, 0x45, 0xc1, 0xd1, 0x1d, 0x10 +}; + +const uint8_t kMaskRandom47_7[42] = { + 0x46, 0x4a, 0x6d, 0xa6, 0xca, 0x6c, + 0x33, 0x24, 0x26, 0x4a, 0x64, 0xa6, + 0x91, 0x92, 0x12, 0x61, 0xa6, 0x0a, + 0xa4, 0x20, 0x4a, 0x0c, 0x90, 0xd8, + 0x50, 0xa0, 0xd5, 0x81, 0x70, 0x36, + 0x84, 0xc5, 0x80, 0x55, 0x45, 0x54, + 0x09, 0x71, 0x0d, 0x50, 0x9d, 0x08 +}; + +const uint8_t kMaskRandom47_8[48] = { + 0x0c, 0x84, 0x0d, 0x02, 0xc0, 0x2c, + 0x80, 0x70, 0x06, 0x80, 0x78, 0x06, + 0xa0, 0x88, 0x48, 0x21, 0x22, 0x12, + 0x05, 0x40, 0x32, 0x0c, 0xa0, 0xca, + 0x43, 0x02, 0x82, 0x40, 0x95, 0x08, + 0x1a, 0x01, 0x51, 0x15, 0x41, 0x54, + 0x60, 0x27, 0x00, 0x66, 0x06, 0x60, + 0x14, 0x38, 0xa0, 0x99, 0x09, 0x90 +}; + +const uint8_t kMaskRandom47_9[54] = { + 0x46, 0x4a, 0x6d, 0xa6, 0xca, 0x6c, + 0x62, 0x7c, 0x84, 0xc8, 0x4c, 0x84, + 0x8c, 0x04, 0x88, 0x30, 0x83, 0x88, + 0x01, 0x74, 0x23, 0x40, 0x94, 0x08, + 0x07, 0x83, 0x07, 0x02, 0x70, 0x26, + 0xa0, 0x80, 0x72, 0x45, 0x44, 0x54, + 0x18, 0xb1, 0x42, 0x10, 0xe1, 0x0e, + 0x91, 0x00, 0x92, 0x09, 0x20, 0x92, + 0x78, 0x00, 0x1c, 0x03, 0x80, 0x38 +}; + +const uint8_t kMaskRandom48_1[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const uint8_t kMaskRandom48_10[60] = { + 0x11, 0x45, 0x14, 0x11, 0x45, 0x14, + 0x45, 0x34, 0x53, 0x45, 0x34, 0x53, + 0x00, 0x48, 0x05, 0x00, 0x48, 0x05, + 0x10, 0x83, 0x09, 0x10, 0x83, 0x09, + 0x4a, 0x14, 0xa1, 0x4a, 0x14, 0xa1, + 0x40, 0xa4, 0x0a, 0x40, 0xa4, 0x0a, + 0xa0, 0x6a, 0x02, 0xa0, 0x6a, 0x02, + 0x88, 0x80, 0x8c, 0x88, 0x80, 0x8c, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x54, 0x0d, 0x40, 0x54, 0x0d, 0x40 +}; + +const uint8_t kMaskRandom48_11[66] = { + 0x53, 0x65, 0x34, 0x53, 0x65, 0x34, + 0xa0, 0x32, 0x11, 0xa0, 0x32, 0x11, + 0x15, 0x11, 0x41, 0x15, 0x11, 0x41, + 0x03, 0x50, 0x15, 0x03, 0x50, 0x15, + 0x8c, 0x88, 0xc8, 0x8c, 0x88, 0xc8, + 0x28, 0x82, 0x88, 0x28, 0x82, 0x88, + 0x08, 0x48, 0x84, 0x08, 0x48, 0x84, + 0x99, 0x01, 0x90, 0x99, 0x01, 0x90, + 0x22, 0x92, 0x29, 0x22, 0x92, 0x29, + 0x46, 0x04, 0x60, 0x46, 0x04, 0x60, + 0x8c, 0x2c, 0x02, 0x8c, 0x2c, 0x02 +}; + +const uint8_t kMaskRandom48_12[72] = { + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44 +}; + +const uint8_t kMaskRandom48_13[78] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86 +}; + +const uint8_t kMaskRandom48_14[84] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0xf2, 0xd6, 0x8e, 0xf2, 0xd6, 0x8e +}; + +const uint8_t kMaskRandom48_15[90] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50 +}; + +const uint8_t kMaskRandom48_16[96] = { + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0xff, 0x6e, 0x0a, 0xff, 0x6e, 0x0a +}; + +const uint8_t kMaskRandom48_17[102] = { + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e +}; + +const uint8_t kMaskRandom48_18[108] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x34, 0x50, 0xae, 0x34, 0x50, 0xae +}; + +const uint8_t kMaskRandom48_19[114] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28 +}; + +const uint8_t kMaskRandom48_2[12] = { + 0xec, 0xce, 0xcc, 0xec, 0xce, 0xcc, + 0x93, 0xb9, 0x3b, 0x93, 0xb9, 0x3b +}; + +const uint8_t kMaskRandom48_20[120] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x98, 0xa2, 0x95, 0x98, 0xa2, 0x95 +}; + +const uint8_t kMaskRandom48_21[126] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02 +}; + +const uint8_t kMaskRandom48_22[132] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x1a, 0xaa, 0xee, 0x1a, 0xaa, 0xee +}; + +const uint8_t kMaskRandom48_23[138] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44 +}; + +const uint8_t kMaskRandom48_24[144] = { + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x88, 0x32, 0x59, 0x88, 0x32, 0x59 +}; + +const uint8_t kMaskRandom48_25[150] = { + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86 +}; + +const uint8_t kMaskRandom48_26[156] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0x3e, 0x20, 0x79, 0xe5, 0x55, 0x70 +}; + +const uint8_t kMaskRandom48_27[162] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0xf2, 0xd6, 0x8e, 0xf2, 0xd6, 0x8e +}; + +const uint8_t kMaskRandom48_28[168] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0xf2, 0xd6, 0x8e, 0xf2, 0xd6, 0x8e, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x32, 0xe3, 0xc0, 0x4a, 0xf2, 0x2a +}; + +const uint8_t kMaskRandom48_29[174] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0xf2, 0xd6, 0x8e, 0xf2, 0xd6, 0x8e, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50 +}; + +const uint8_t kMaskRandom48_3[18] = { + 0x9b, 0x29, 0xb2, 0x9b, 0x29, 0xb2, + 0x49, 0xd4, 0x9d, 0x49, 0xd4, 0x9d, + 0x3e, 0x83, 0xe8, 0x3e, 0x83, 0xe8 +}; + +const uint8_t kMaskRandom48_30[180] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0xc5, 0x1c, 0x51, 0xc5, 0x1c, 0x51, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x12, 0x31, 0x23, 0x12, 0x31, 0x23, + 0x08, 0xe0, 0x8e, 0x08, 0xe0, 0x8e, + 0x2e, 0x02, 0xe0, 0x2e, 0x02, 0xe0, + 0xf2, 0xd6, 0x8e, 0xf2, 0xd6, 0x8e, + 0x66, 0xf3, 0x9a, 0xdd, 0x68, 0x93 +}; + +const uint8_t kMaskRandom48_31[186] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0xff, 0x6e, 0x0a, 0xff, 0x6e, 0x0a +}; + +const uint8_t kMaskRandom48_32[192] = { + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0xff, 0x6e, 0x0a, 0xff, 0x6e, 0x0a, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0xd5, 0x4a, 0x4f, 0x48, 0xb5, 0x31 +}; + +const uint8_t kMaskRandom48_33[198] = { + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0xff, 0x6e, 0x0a, 0xff, 0x6e, 0x0a, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e +}; + +const uint8_t kMaskRandom48_34[204] = { + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x90, 0x99, 0x09, 0x90, 0x99, 0x09, + 0x02, 0x50, 0x25, 0x02, 0x50, 0x25, + 0x06, 0xa0, 0x6a, 0x06, 0xa0, 0x6a, + 0x2c, 0x02, 0xc0, 0x2c, 0x02, 0xc0, + 0x88, 0x68, 0x86, 0x88, 0x68, 0x86, + 0xff, 0x6e, 0x0a, 0xff, 0x6e, 0x0a, + 0x40, 0x72, 0x4c, 0xe8, 0xf2, 0x42 +}; + +const uint8_t kMaskRandom48_35[210] = { + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x34, 0x50, 0xae, 0x34, 0x50, 0xae +}; + +const uint8_t kMaskRandom48_36[216] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x34, 0x50, 0xae, 0x34, 0x50, 0xae, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x71, 0xba, 0x8b, 0xf3, 0xfa, 0x9d +}; + +const uint8_t kMaskRandom48_37[222] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x34, 0x50, 0xae, 0x34, 0x50, 0xae, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28 +}; + +const uint8_t kMaskRandom48_38[228] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x20, 0x62, 0x06, 0x20, 0x62, 0x06, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, + 0x42, 0x44, 0x24, 0x42, 0x44, 0x24, + 0x01, 0x90, 0x19, 0x01, 0x90, 0x19, + 0x14, 0x11, 0x41, 0x14, 0x11, 0x41, + 0x0a, 0x80, 0xa8, 0x0a, 0x80, 0xa8, + 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, + 0xc5, 0x0c, 0x50, 0xc5, 0x0c, 0x50, + 0x34, 0x50, 0xae, 0x34, 0x50, 0xae, + 0x2a, 0x7a, 0xf6, 0x8c, 0xde, 0x51 +}; + +const uint8_t kMaskRandom48_39[234] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x98, 0xa2, 0x95, 0x98, 0xa2, 0x95 +}; + +const uint8_t kMaskRandom48_4[24] = { + 0x8b, 0x28, 0xb2, 0x8b, 0x28, 0xb2, + 0x14, 0xb1, 0x4b, 0x14, 0xb1, 0x4b, + 0x22, 0xd2, 0x2d, 0x22, 0xd2, 0x2d, + 0x45, 0x54, 0x55, 0x45, 0x54, 0x55 +}; + +const uint8_t kMaskRandom48_40[240] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x98, 0xa2, 0x95, 0x98, 0xa2, 0x95, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x20, 0x5f, 0x68, 0xd5, 0xa2, 0x1b +}; + +const uint8_t kMaskRandom48_41[246] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x98, 0xa2, 0x95, 0x98, 0xa2, 0x95, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02 +}; + +const uint8_t kMaskRandom48_42[252] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0xe4, 0x2e, 0x42, 0xe4, 0x2e, 0x42, + 0x24, 0x42, 0x44, 0x24, 0x42, 0x44, + 0xa1, 0x1a, 0x11, 0xa1, 0x1a, 0x11, + 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0x03, 0x90, 0x39, 0x03, 0x90, 0x39, + 0x8a, 0x18, 0xa1, 0x8a, 0x18, 0xa1, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0x98, 0xa2, 0x95, 0x98, 0xa2, 0x95, + 0x66, 0xcf, 0xa3, 0x47, 0x69, 0x00 +}; + +const uint8_t kMaskRandom48_43[258] = { + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x1a, 0xaa, 0xee, 0x1a, 0xaa, 0xee +}; + +const uint8_t kMaskRandom48_44[264] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x1a, 0xaa, 0xee, 0x1a, 0xaa, 0xee, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0xc6, 0x40, 0x1f, 0x57, 0xc6, 0xe6 +}; + +const uint8_t kMaskRandom48_45[270] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x1a, 0xaa, 0xee, 0x1a, 0xaa, 0xee, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44 +}; + +const uint8_t kMaskRandom48_46[276] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x51, 0x45, 0x14, 0x51, 0x45, 0x14, + 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, + 0x80, 0xd8, 0x0d, 0x80, 0xd8, 0x0d, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x0a, 0x20, 0xa2, 0x0a, 0x20, 0xa2, + 0x00, 0xe0, 0x0e, 0x00, 0xe0, 0x0e, + 0xb8, 0x0b, 0x80, 0xb8, 0x0b, 0x80, + 0x09, 0x10, 0x91, 0x09, 0x10, 0x91, + 0x56, 0x05, 0x60, 0x56, 0x05, 0x60, + 0xa2, 0x8a, 0x28, 0xa2, 0x8a, 0x28, + 0x1a, 0xaa, 0xee, 0x1a, 0xaa, 0xee, + 0x10, 0xf9, 0xab, 0x12, 0x14, 0xef +}; + +const uint8_t kMaskRandom48_47[282] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x88, 0x32, 0x59, 0x88, 0x32, 0x59 +}; + +const uint8_t kMaskRandom48_48[288] = { + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x88, 0x32, 0x59, 0x88, 0x32, 0x59, + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x21, 0x32, 0x13, 0x21, 0x32, 0x13, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x0c, 0x10, 0xc1, 0x0c, 0x10, 0xc1, + 0x40, 0xc4, 0x0c, 0x40, 0xc4, 0x0c, + 0x6a, 0x06, 0xa0, 0x6a, 0x06, 0xa0, + 0x86, 0x08, 0x60, 0x86, 0x08, 0x60, + 0x24, 0x82, 0x48, 0x24, 0x82, 0x48, + 0x89, 0x08, 0x90, 0x89, 0x08, 0x90, + 0xc0, 0x2c, 0x02, 0xc0, 0x2c, 0x02, + 0x10, 0x61, 0x06, 0x10, 0x61, 0x06, + 0x02, 0x30, 0x23, 0x02, 0x30, 0x23, + 0x40, 0x54, 0x05, 0x40, 0x54, 0x05, + 0x21, 0x82, 0x18, 0x21, 0x82, 0x18, + 0x81, 0x18, 0x11, 0x81, 0x18, 0x11, + 0x14, 0x81, 0x48, 0x14, 0x81, 0x48, + 0x98, 0x09, 0x80, 0x98, 0x09, 0x80, + 0x08, 0x90, 0x89, 0x08, 0x90, 0x89, + 0x62, 0x06, 0x20, 0x62, 0x06, 0x20, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x8a, 0x08, 0xa0, 0x8a, 0x08, 0xa0, + 0x84, 0x48, 0x44, 0x84, 0x48, 0x44, + 0xff, 0x9b, 0xdf, 0xec, 0xae, 0x0e +}; + +const uint8_t kMaskRandom48_5[30] = { + 0x53, 0x65, 0x36, 0x53, 0x65, 0x36, + 0x64, 0xb6, 0x4b, 0x64, 0xb6, 0x4b, + 0x0e, 0xe0, 0xee, 0x0e, 0xe0, 0xee, + 0xa9, 0xca, 0x9c, 0xa9, 0xca, 0x9c, + 0xb8, 0x3b, 0x83, 0xb8, 0x3b, 0x83 +}; + +const uint8_t kMaskRandom48_6[36] = { + 0xd1, 0x4d, 0x14, 0xd1, 0x4d, 0x14, + 0x45, 0x34, 0x53, 0x45, 0x34, 0x53, + 0x22, 0xd2, 0x2d, 0x22, 0xd2, 0x2d, + 0x16, 0xc1, 0x6c, 0x16, 0xc1, 0x6c, + 0x0b, 0xa0, 0xba, 0x0b, 0xa0, 0xba, + 0xe8, 0x8e, 0x88, 0xe8, 0x8e, 0x88 +}; + +const uint8_t kMaskRandom48_7[42] = { + 0xd3, 0x65, 0x36, 0xd3, 0x65, 0x36, + 0x25, 0x32, 0x53, 0x25, 0x32, 0x53, + 0x30, 0xd3, 0x05, 0x30, 0xd3, 0x05, + 0x06, 0x48, 0x6c, 0x06, 0x48, 0x6c, + 0xc0, 0xb8, 0x1b, 0xc0, 0xb8, 0x1b, + 0x2a, 0xa2, 0xaa, 0x2a, 0xa2, 0xaa, + 0xa8, 0x4e, 0x84, 0xa8, 0x4e, 0x84 +}; + +const uint8_t kMaskRandom48_8[48] = { + 0x81, 0x60, 0x16, 0x81, 0x60, 0x16, + 0x40, 0x3c, 0x03, 0x40, 0x3c, 0x03, + 0x10, 0x91, 0x09, 0x10, 0x91, 0x09, + 0x06, 0x50, 0x65, 0x06, 0x50, 0x65, + 0x20, 0x4a, 0x84, 0x20, 0x4a, 0x84, + 0x8a, 0xa0, 0xaa, 0x8a, 0xa0, 0xaa, + 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, + 0x4c, 0x84, 0xc8, 0x4c, 0x84, 0xc8 +}; + +const uint8_t kMaskRandom48_9[54] = { + 0xd3, 0x65, 0x36, 0xd3, 0x65, 0x36, + 0x64, 0x26, 0x42, 0x64, 0x26, 0x42, + 0x18, 0x41, 0xc4, 0x18, 0x41, 0xc4, + 0xa0, 0x4a, 0x04, 0xa0, 0x4a, 0x04, + 0x81, 0x38, 0x13, 0x81, 0x38, 0x13, + 0x22, 0xa2, 0x2a, 0x22, 0xa2, 0x2a, + 0x08, 0x70, 0x87, 0x08, 0x70, 0x87, + 0x04, 0x90, 0x49, 0x04, 0x90, 0x49, + 0x01, 0xc0, 0x1c, 0x01, 0xc0, 0x1c +}; + +const uint8_t kMaskRandom4_1[2] = { + 0xf0, 0x00 +}; + +const uint8_t kMaskRandom4_2[4] = { + 0xc0, 0x00, + 0xb0, 0x00 +}; + +const uint8_t kMaskRandom4_3[6] = { + 0xc0, 0x00, + 0xb0, 0x00, + 0x60, 0x00 +}; + +const uint8_t kMaskRandom4_4[8] = { + 0xc0, 0x00, + 0xa0, 0x00, + 0x30, 0x00, + 0x50, 0x00 +}; + +const uint8_t kMaskRandom5_1[2] = { + 0xf8, 0x00 +}; + +const uint8_t kMaskRandom5_2[4] = { + 0xa8, 0x00, + 0xd0, 0x00 +}; + +const uint8_t kMaskRandom5_3[6] = { + 0xb0, 0x00, + 0xc8, 0x00, + 0x50, 0x00 +}; + +const uint8_t kMaskRandom5_4[8] = { + 0xc8, 0x00, + 0xb0, 0x00, + 0x50, 0x00, + 0x28, 0x00 +}; + +const uint8_t kMaskRandom5_5[10] = { + 0xc0, 0x00, + 0x30, 0x00, + 0x18, 0x00, + 0xa0, 0x00, + 0x48, 0x00 +}; + +const uint8_t kMaskRandom6_1[2] = { + 0xfc, 0x00 +}; + +const uint8_t kMaskRandom6_2[4] = { + 0xa8, 0x00, + 0xd4, 0x00 +}; + +const uint8_t kMaskRandom6_3[6] = { + 0xd0, 0x00, + 0x68, 0x00, + 0xa4, 0x00 +}; + +const uint8_t kMaskRandom6_4[8] = { + 0xa8, 0x00, + 0x58, 0x00, + 0x64, 0x00, + 0x94, 0x00 +}; + +const uint8_t kMaskRandom6_5[10] = { + 0xa8, 0x00, + 0x84, 0x00, + 0x64, 0x00, + 0x90, 0x00, + 0x58, 0x00 +}; + +const uint8_t kMaskRandom6_6[12] = { + 0x98, 0x00, + 0x64, 0x00, + 0x50, 0x00, + 0x14, 0x00, + 0xa8, 0x00, + 0xe0, 0x00 +}; + +const uint8_t kMaskRandom7_1[2] = { + 0xfe, 0x00 +}; + +const uint8_t kMaskRandom7_2[4] = { + 0xd4, 0x00, + 0xaa, 0x00 +}; + +const uint8_t kMaskRandom7_3[6] = { + 0xd0, 0x00, + 0xaa, 0x00, + 0x64, 0x00 +}; + +const uint8_t kMaskRandom7_4[8] = { + 0xd0, 0x00, + 0xaa, 0x00, + 0x64, 0x00, + 0x1c, 0x00 +}; + +const uint8_t kMaskRandom7_5[10] = { + 0x0c, 0x00, + 0xb0, 0x00, + 0x1a, 0x00, + 0xc4, 0x00, + 0x62, 0x00 +}; + +const uint8_t kMaskRandom7_6[12] = { + 0x8c, 0x00, + 0x4a, 0x00, + 0x64, 0x00, + 0xd0, 0x00, + 0xa0, 0x00, + 0x32, 0x00 +}; + +const uint8_t kMaskRandom7_7[14] = { + 0x4a, 0x00, + 0x94, 0x00, + 0x1a, 0x00, + 0xc4, 0x00, + 0x28, 0x00, + 0xc2, 0x00, + 0x34, 0x00 +}; + +const uint8_t kMaskRandom8_1[2] = { + 0xff, 0x00 +}; + +const uint8_t kMaskRandom8_2[4] = { + 0xaa, 0x00, + 0xd5, 0x00 +}; + +const uint8_t kMaskRandom8_3[6] = { + 0xc5, 0x00, + 0x92, 0x00, + 0x6a, 0x00 +}; + +const uint8_t kMaskRandom8_4[8] = { + 0x45, 0x00, + 0xb4, 0x00, + 0x6a, 0x00, + 0x89, 0x00 +}; + +const uint8_t kMaskRandom8_5[10] = { + 0x8c, 0x00, + 0x92, 0x00, + 0x2b, 0x00, + 0x51, 0x00, + 0x64, 0x00 +}; + +const uint8_t kMaskRandom8_6[12] = { + 0xa1, 0x00, + 0x52, 0x00, + 0x91, 0x00, + 0x2a, 0x00, + 0xc4, 0x00, + 0x4c, 0x00 +}; + +const uint8_t kMaskRandom8_7[14] = { + 0x15, 0x00, + 0xc2, 0x00, + 0x25, 0x00, + 0x62, 0x00, + 0x58, 0x00, + 0x8c, 0x00, + 0xa3, 0x00 +}; + +const uint8_t kMaskRandom8_8[16] = { + 0x25, 0x00, + 0x8a, 0x00, + 0x91, 0x00, + 0x68, 0x00, + 0x32, 0x00, + 0x43, 0x00, + 0xc4, 0x00, + 0x1c, 0x00 +}; + +const uint8_t kMaskRandom9_1[2] = { + 0xff, 0x80 +}; + +const uint8_t kMaskRandom9_2[4] = { + 0xaa, 0x80, + 0xd5, 0x00 +}; + +const uint8_t kMaskRandom9_3[6] = { + 0xa5, 0x00, + 0xc8, 0x00, + 0x52, 0x80 +}; + +const uint8_t kMaskRandom9_4[8] = { + 0xa2, 0x00, + 0xc9, 0x00, + 0x52, 0x80, + 0x24, 0x80 +}; + +const uint8_t kMaskRandom9_5[10] = { + 0x8c, 0x00, + 0x25, 0x00, + 0x92, 0x80, + 0x41, 0x80, + 0x58, 0x00 +}; + +const uint8_t kMaskRandom9_6[12] = { + 0x84, 0x80, + 0x27, 0x00, + 0x51, 0x80, + 0x1a, 0x00, + 0x68, 0x00, + 0x89, 0x00 +}; + +const uint8_t kMaskRandom9_7[14] = { + 0x8c, 0x00, + 0x47, 0x00, + 0x81, 0x80, + 0x12, 0x80, + 0x58, 0x00, + 0x28, 0x80, + 0xb4, 0x00 +}; + +const uint8_t kMaskRandom9_8[16] = { + 0x2c, 0x00, + 0x91, 0x00, + 0x40, 0x80, + 0x06, 0x80, + 0xc8, 0x00, + 0x45, 0x00, + 0x30, 0x80, + 0xa2, 0x00 +}; + +const uint8_t kMaskRandom9_9[18] = { + 0x4c, 0x00, + 0x62, 0x00, + 0x91, 0x00, + 0x42, 0x80, + 0xa4, 0x00, + 0x13, 0x00, + 0x30, 0x80, + 0x88, 0x80, + 0x09, 0x00 +}; + +const uint8_t* const kPacketMaskRandom1[1] = { + kMaskRandom1_1 +}; + +const uint8_t* const kPacketMaskRandom2[2] = { + kMaskRandom2_1, + kMaskRandom2_2 +}; + +const uint8_t* const kPacketMaskRandom3[3] = { + kMaskRandom3_1, + kMaskRandom3_2, + kMaskRandom3_3 +}; + +const uint8_t* const kPacketMaskRandom4[4] = { + kMaskRandom4_1, + kMaskRandom4_2, + kMaskRandom4_3, + kMaskRandom4_4 +}; + +const uint8_t* const kPacketMaskRandom5[5] = { + kMaskRandom5_1, + kMaskRandom5_2, + kMaskRandom5_3, + kMaskRandom5_4, + kMaskRandom5_5 +}; + +const uint8_t* const kPacketMaskRandom6[6] = { + kMaskRandom6_1, + kMaskRandom6_2, + kMaskRandom6_3, + kMaskRandom6_4, + kMaskRandom6_5, + kMaskRandom6_6 +}; + +const uint8_t* const kPacketMaskRandom7[7] = { + kMaskRandom7_1, + kMaskRandom7_2, + kMaskRandom7_3, + kMaskRandom7_4, + kMaskRandom7_5, + kMaskRandom7_6, + kMaskRandom7_7 +}; + +const uint8_t* const kPacketMaskRandom8[8] = { + kMaskRandom8_1, + kMaskRandom8_2, + kMaskRandom8_3, + kMaskRandom8_4, + kMaskRandom8_5, + kMaskRandom8_6, + kMaskRandom8_7, + kMaskRandom8_8 +}; + +const uint8_t* const kPacketMaskRandom9[9] = { + kMaskRandom9_1, + kMaskRandom9_2, + kMaskRandom9_3, + kMaskRandom9_4, + kMaskRandom9_5, + kMaskRandom9_6, + kMaskRandom9_7, + kMaskRandom9_8, + kMaskRandom9_9 +}; + +const uint8_t* const kPacketMaskRandom10[10] = { + kMaskRandom10_1, + kMaskRandom10_2, + kMaskRandom10_3, + kMaskRandom10_4, + kMaskRandom10_5, + kMaskRandom10_6, + kMaskRandom10_7, + kMaskRandom10_8, + kMaskRandom10_9, + kMaskRandom10_10 +}; + +const uint8_t* const kPacketMaskRandom11[11] = { + kMaskRandom11_1, + kMaskRandom11_2, + kMaskRandom11_3, + kMaskRandom11_4, + kMaskRandom11_5, + kMaskRandom11_6, + kMaskRandom11_7, + kMaskRandom11_8, + kMaskRandom11_9, + kMaskRandom11_10, + kMaskRandom11_11 +}; + +const uint8_t* const kPacketMaskRandom12[12] = { + kMaskRandom12_1, + kMaskRandom12_2, + kMaskRandom12_3, + kMaskRandom12_4, + kMaskRandom12_5, + kMaskRandom12_6, + kMaskRandom12_7, + kMaskRandom12_8, + kMaskRandom12_9, + kMaskRandom12_10, + kMaskRandom12_11, + kMaskRandom12_12 +}; + +const uint8_t* const kPacketMaskRandom13[13] = { + kMaskRandom13_1, + kMaskRandom13_2, + kMaskRandom13_3, + kMaskRandom13_4, + kMaskRandom13_5, + kMaskRandom13_6, + kMaskRandom13_7, + kMaskRandom13_8, + kMaskRandom13_9, + kMaskRandom13_10, + kMaskRandom13_11, + kMaskRandom13_12, + kMaskRandom13_13 +}; + +const uint8_t* const kPacketMaskRandom14[14] = { + kMaskRandom14_1, + kMaskRandom14_2, + kMaskRandom14_3, + kMaskRandom14_4, + kMaskRandom14_5, + kMaskRandom14_6, + kMaskRandom14_7, + kMaskRandom14_8, + kMaskRandom14_9, + kMaskRandom14_10, + kMaskRandom14_11, + kMaskRandom14_12, + kMaskRandom14_13, + kMaskRandom14_14 +}; + +const uint8_t* const kPacketMaskRandom15[15] = { + kMaskRandom15_1, + kMaskRandom15_2, + kMaskRandom15_3, + kMaskRandom15_4, + kMaskRandom15_5, + kMaskRandom15_6, + kMaskRandom15_7, + kMaskRandom15_8, + kMaskRandom15_9, + kMaskRandom15_10, + kMaskRandom15_11, + kMaskRandom15_12, + kMaskRandom15_13, + kMaskRandom15_14, + kMaskRandom15_15 +}; + +const uint8_t* const kPacketMaskRandom16[16] = { + kMaskRandom16_1, + kMaskRandom16_2, + kMaskRandom16_3, + kMaskRandom16_4, + kMaskRandom16_5, + kMaskRandom16_6, + kMaskRandom16_7, + kMaskRandom16_8, + kMaskRandom16_9, + kMaskRandom16_10, + kMaskRandom16_11, + kMaskRandom16_12, + kMaskRandom16_13, + kMaskRandom16_14, + kMaskRandom16_15, + kMaskRandom16_16 +}; + +const uint8_t* const kPacketMaskRandom17[17] = { + kMaskRandom17_1, + kMaskRandom17_2, + kMaskRandom17_3, + kMaskRandom17_4, + kMaskRandom17_5, + kMaskRandom17_6, + kMaskRandom17_7, + kMaskRandom17_8, + kMaskRandom17_9, + kMaskRandom17_10, + kMaskRandom17_11, + kMaskRandom17_12, + kMaskRandom17_13, + kMaskRandom17_14, + kMaskRandom17_15, + kMaskRandom17_16, + kMaskRandom17_17 +}; + +const uint8_t* const kPacketMaskRandom18[18] = { + kMaskRandom18_1, + kMaskRandom18_2, + kMaskRandom18_3, + kMaskRandom18_4, + kMaskRandom18_5, + kMaskRandom18_6, + kMaskRandom18_7, + kMaskRandom18_8, + kMaskRandom18_9, + kMaskRandom18_10, + kMaskRandom18_11, + kMaskRandom18_12, + kMaskRandom18_13, + kMaskRandom18_14, + kMaskRandom18_15, + kMaskRandom18_16, + kMaskRandom18_17, + kMaskRandom18_18 +}; + +const uint8_t* const kPacketMaskRandom19[19] = { + kMaskRandom19_1, + kMaskRandom19_2, + kMaskRandom19_3, + kMaskRandom19_4, + kMaskRandom19_5, + kMaskRandom19_6, + kMaskRandom19_7, + kMaskRandom19_8, + kMaskRandom19_9, + kMaskRandom19_10, + kMaskRandom19_11, + kMaskRandom19_12, + kMaskRandom19_13, + kMaskRandom19_14, + kMaskRandom19_15, + kMaskRandom19_16, + kMaskRandom19_17, + kMaskRandom19_18, + kMaskRandom19_19 +}; + +const uint8_t* const kPacketMaskRandom20[20] = { + kMaskRandom20_1, + kMaskRandom20_2, + kMaskRandom20_3, + kMaskRandom20_4, + kMaskRandom20_5, + kMaskRandom20_6, + kMaskRandom20_7, + kMaskRandom20_8, + kMaskRandom20_9, + kMaskRandom20_10, + kMaskRandom20_11, + kMaskRandom20_12, + kMaskRandom20_13, + kMaskRandom20_14, + kMaskRandom20_15, + kMaskRandom20_16, + kMaskRandom20_17, + kMaskRandom20_18, + kMaskRandom20_19, + kMaskRandom20_20 +}; + +const uint8_t* const kPacketMaskRandom21[21] = { + kMaskRandom21_1, + kMaskRandom21_2, + kMaskRandom21_3, + kMaskRandom21_4, + kMaskRandom21_5, + kMaskRandom21_6, + kMaskRandom21_7, + kMaskRandom21_8, + kMaskRandom21_9, + kMaskRandom21_10, + kMaskRandom21_11, + kMaskRandom21_12, + kMaskRandom21_13, + kMaskRandom21_14, + kMaskRandom21_15, + kMaskRandom21_16, + kMaskRandom21_17, + kMaskRandom21_18, + kMaskRandom21_19, + kMaskRandom21_20, + kMaskRandom21_21 +}; + +const uint8_t* const kPacketMaskRandom22[22] = { + kMaskRandom22_1, + kMaskRandom22_2, + kMaskRandom22_3, + kMaskRandom22_4, + kMaskRandom22_5, + kMaskRandom22_6, + kMaskRandom22_7, + kMaskRandom22_8, + kMaskRandom22_9, + kMaskRandom22_10, + kMaskRandom22_11, + kMaskRandom22_12, + kMaskRandom22_13, + kMaskRandom22_14, + kMaskRandom22_15, + kMaskRandom22_16, + kMaskRandom22_17, + kMaskRandom22_18, + kMaskRandom22_19, + kMaskRandom22_20, + kMaskRandom22_21, + kMaskRandom22_22 +}; + +const uint8_t* const kPacketMaskRandom23[23] = { + kMaskRandom23_1, + kMaskRandom23_2, + kMaskRandom23_3, + kMaskRandom23_4, + kMaskRandom23_5, + kMaskRandom23_6, + kMaskRandom23_7, + kMaskRandom23_8, + kMaskRandom23_9, + kMaskRandom23_10, + kMaskRandom23_11, + kMaskRandom23_12, + kMaskRandom23_13, + kMaskRandom23_14, + kMaskRandom23_15, + kMaskRandom23_16, + kMaskRandom23_17, + kMaskRandom23_18, + kMaskRandom23_19, + kMaskRandom23_20, + kMaskRandom23_21, + kMaskRandom23_22, + kMaskRandom23_23 +}; + +const uint8_t* const kPacketMaskRandom24[24] = { + kMaskRandom24_1, + kMaskRandom24_2, + kMaskRandom24_3, + kMaskRandom24_4, + kMaskRandom24_5, + kMaskRandom24_6, + kMaskRandom24_7, + kMaskRandom24_8, + kMaskRandom24_9, + kMaskRandom24_10, + kMaskRandom24_11, + kMaskRandom24_12, + kMaskRandom24_13, + kMaskRandom24_14, + kMaskRandom24_15, + kMaskRandom24_16, + kMaskRandom24_17, + kMaskRandom24_18, + kMaskRandom24_19, + kMaskRandom24_20, + kMaskRandom24_21, + kMaskRandom24_22, + kMaskRandom24_23, + kMaskRandom24_24 +}; + +const uint8_t* const kPacketMaskRandom25[25] = { + kMaskRandom25_1, + kMaskRandom25_2, + kMaskRandom25_3, + kMaskRandom25_4, + kMaskRandom25_5, + kMaskRandom25_6, + kMaskRandom25_7, + kMaskRandom25_8, + kMaskRandom25_9, + kMaskRandom25_10, + kMaskRandom25_11, + kMaskRandom25_12, + kMaskRandom25_13, + kMaskRandom25_14, + kMaskRandom25_15, + kMaskRandom25_16, + kMaskRandom25_17, + kMaskRandom25_18, + kMaskRandom25_19, + kMaskRandom25_20, + kMaskRandom25_21, + kMaskRandom25_22, + kMaskRandom25_23, + kMaskRandom25_24, + kMaskRandom25_25 +}; + +const uint8_t* const kPacketMaskRandom26[26] = { + kMaskRandom26_1, + kMaskRandom26_2, + kMaskRandom26_3, + kMaskRandom26_4, + kMaskRandom26_5, + kMaskRandom26_6, + kMaskRandom26_7, + kMaskRandom26_8, + kMaskRandom26_9, + kMaskRandom26_10, + kMaskRandom26_11, + kMaskRandom26_12, + kMaskRandom26_13, + kMaskRandom26_14, + kMaskRandom26_15, + kMaskRandom26_16, + kMaskRandom26_17, + kMaskRandom26_18, + kMaskRandom26_19, + kMaskRandom26_20, + kMaskRandom26_21, + kMaskRandom26_22, + kMaskRandom26_23, + kMaskRandom26_24, + kMaskRandom26_25, + kMaskRandom26_26 +}; + +const uint8_t* const kPacketMaskRandom27[27] = { + kMaskRandom27_1, + kMaskRandom27_2, + kMaskRandom27_3, + kMaskRandom27_4, + kMaskRandom27_5, + kMaskRandom27_6, + kMaskRandom27_7, + kMaskRandom27_8, + kMaskRandom27_9, + kMaskRandom27_10, + kMaskRandom27_11, + kMaskRandom27_12, + kMaskRandom27_13, + kMaskRandom27_14, + kMaskRandom27_15, + kMaskRandom27_16, + kMaskRandom27_17, + kMaskRandom27_18, + kMaskRandom27_19, + kMaskRandom27_20, + kMaskRandom27_21, + kMaskRandom27_22, + kMaskRandom27_23, + kMaskRandom27_24, + kMaskRandom27_25, + kMaskRandom27_26, + kMaskRandom27_27 +}; + +const uint8_t* const kPacketMaskRandom28[28] = { + kMaskRandom28_1, + kMaskRandom28_2, + kMaskRandom28_3, + kMaskRandom28_4, + kMaskRandom28_5, + kMaskRandom28_6, + kMaskRandom28_7, + kMaskRandom28_8, + kMaskRandom28_9, + kMaskRandom28_10, + kMaskRandom28_11, + kMaskRandom28_12, + kMaskRandom28_13, + kMaskRandom28_14, + kMaskRandom28_15, + kMaskRandom28_16, + kMaskRandom28_17, + kMaskRandom28_18, + kMaskRandom28_19, + kMaskRandom28_20, + kMaskRandom28_21, + kMaskRandom28_22, + kMaskRandom28_23, + kMaskRandom28_24, + kMaskRandom28_25, + kMaskRandom28_26, + kMaskRandom28_27, + kMaskRandom28_28 +}; + +const uint8_t* const kPacketMaskRandom29[29] = { + kMaskRandom29_1, + kMaskRandom29_2, + kMaskRandom29_3, + kMaskRandom29_4, + kMaskRandom29_5, + kMaskRandom29_6, + kMaskRandom29_7, + kMaskRandom29_8, + kMaskRandom29_9, + kMaskRandom29_10, + kMaskRandom29_11, + kMaskRandom29_12, + kMaskRandom29_13, + kMaskRandom29_14, + kMaskRandom29_15, + kMaskRandom29_16, + kMaskRandom29_17, + kMaskRandom29_18, + kMaskRandom29_19, + kMaskRandom29_20, + kMaskRandom29_21, + kMaskRandom29_22, + kMaskRandom29_23, + kMaskRandom29_24, + kMaskRandom29_25, + kMaskRandom29_26, + kMaskRandom29_27, + kMaskRandom29_28, + kMaskRandom29_29 +}; + +const uint8_t* const kPacketMaskRandom30[30] = { + kMaskRandom30_1, + kMaskRandom30_2, + kMaskRandom30_3, + kMaskRandom30_4, + kMaskRandom30_5, + kMaskRandom30_6, + kMaskRandom30_7, + kMaskRandom30_8, + kMaskRandom30_9, + kMaskRandom30_10, + kMaskRandom30_11, + kMaskRandom30_12, + kMaskRandom30_13, + kMaskRandom30_14, + kMaskRandom30_15, + kMaskRandom30_16, + kMaskRandom30_17, + kMaskRandom30_18, + kMaskRandom30_19, + kMaskRandom30_20, + kMaskRandom30_21, + kMaskRandom30_22, + kMaskRandom30_23, + kMaskRandom30_24, + kMaskRandom30_25, + kMaskRandom30_26, + kMaskRandom30_27, + kMaskRandom30_28, + kMaskRandom30_29, + kMaskRandom30_30 +}; + +const uint8_t* const kPacketMaskRandom31[31] = { + kMaskRandom31_1, + kMaskRandom31_2, + kMaskRandom31_3, + kMaskRandom31_4, + kMaskRandom31_5, + kMaskRandom31_6, + kMaskRandom31_7, + kMaskRandom31_8, + kMaskRandom31_9, + kMaskRandom31_10, + kMaskRandom31_11, + kMaskRandom31_12, + kMaskRandom31_13, + kMaskRandom31_14, + kMaskRandom31_15, + kMaskRandom31_16, + kMaskRandom31_17, + kMaskRandom31_18, + kMaskRandom31_19, + kMaskRandom31_20, + kMaskRandom31_21, + kMaskRandom31_22, + kMaskRandom31_23, + kMaskRandom31_24, + kMaskRandom31_25, + kMaskRandom31_26, + kMaskRandom31_27, + kMaskRandom31_28, + kMaskRandom31_29, + kMaskRandom31_30, + kMaskRandom31_31 +}; + +const uint8_t* const kPacketMaskRandom32[32] = { + kMaskRandom32_1, + kMaskRandom32_2, + kMaskRandom32_3, + kMaskRandom32_4, + kMaskRandom32_5, + kMaskRandom32_6, + kMaskRandom32_7, + kMaskRandom32_8, + kMaskRandom32_9, + kMaskRandom32_10, + kMaskRandom32_11, + kMaskRandom32_12, + kMaskRandom32_13, + kMaskRandom32_14, + kMaskRandom32_15, + kMaskRandom32_16, + kMaskRandom32_17, + kMaskRandom32_18, + kMaskRandom32_19, + kMaskRandom32_20, + kMaskRandom32_21, + kMaskRandom32_22, + kMaskRandom32_23, + kMaskRandom32_24, + kMaskRandom32_25, + kMaskRandom32_26, + kMaskRandom32_27, + kMaskRandom32_28, + kMaskRandom32_29, + kMaskRandom32_30, + kMaskRandom32_31, + kMaskRandom32_32 +}; + +const uint8_t* const kPacketMaskRandom33[33] = { + kMaskRandom33_1, + kMaskRandom33_2, + kMaskRandom33_3, + kMaskRandom33_4, + kMaskRandom33_5, + kMaskRandom33_6, + kMaskRandom33_7, + kMaskRandom33_8, + kMaskRandom33_9, + kMaskRandom33_10, + kMaskRandom33_11, + kMaskRandom33_12, + kMaskRandom33_13, + kMaskRandom33_14, + kMaskRandom33_15, + kMaskRandom33_16, + kMaskRandom33_17, + kMaskRandom33_18, + kMaskRandom33_19, + kMaskRandom33_20, + kMaskRandom33_21, + kMaskRandom33_22, + kMaskRandom33_23, + kMaskRandom33_24, + kMaskRandom33_25, + kMaskRandom33_26, + kMaskRandom33_27, + kMaskRandom33_28, + kMaskRandom33_29, + kMaskRandom33_30, + kMaskRandom33_31, + kMaskRandom33_32, + kMaskRandom33_33 +}; + +const uint8_t* const kPacketMaskRandom34[34] = { + kMaskRandom34_1, + kMaskRandom34_2, + kMaskRandom34_3, + kMaskRandom34_4, + kMaskRandom34_5, + kMaskRandom34_6, + kMaskRandom34_7, + kMaskRandom34_8, + kMaskRandom34_9, + kMaskRandom34_10, + kMaskRandom34_11, + kMaskRandom34_12, + kMaskRandom34_13, + kMaskRandom34_14, + kMaskRandom34_15, + kMaskRandom34_16, + kMaskRandom34_17, + kMaskRandom34_18, + kMaskRandom34_19, + kMaskRandom34_20, + kMaskRandom34_21, + kMaskRandom34_22, + kMaskRandom34_23, + kMaskRandom34_24, + kMaskRandom34_25, + kMaskRandom34_26, + kMaskRandom34_27, + kMaskRandom34_28, + kMaskRandom34_29, + kMaskRandom34_30, + kMaskRandom34_31, + kMaskRandom34_32, + kMaskRandom34_33, + kMaskRandom34_34 +}; + +const uint8_t* const kPacketMaskRandom35[35] = { + kMaskRandom35_1, + kMaskRandom35_2, + kMaskRandom35_3, + kMaskRandom35_4, + kMaskRandom35_5, + kMaskRandom35_6, + kMaskRandom35_7, + kMaskRandom35_8, + kMaskRandom35_9, + kMaskRandom35_10, + kMaskRandom35_11, + kMaskRandom35_12, + kMaskRandom35_13, + kMaskRandom35_14, + kMaskRandom35_15, + kMaskRandom35_16, + kMaskRandom35_17, + kMaskRandom35_18, + kMaskRandom35_19, + kMaskRandom35_20, + kMaskRandom35_21, + kMaskRandom35_22, + kMaskRandom35_23, + kMaskRandom35_24, + kMaskRandom35_25, + kMaskRandom35_26, + kMaskRandom35_27, + kMaskRandom35_28, + kMaskRandom35_29, + kMaskRandom35_30, + kMaskRandom35_31, + kMaskRandom35_32, + kMaskRandom35_33, + kMaskRandom35_34, + kMaskRandom35_35 +}; + +const uint8_t* const kPacketMaskRandom36[36] = { + kMaskRandom36_1, + kMaskRandom36_2, + kMaskRandom36_3, + kMaskRandom36_4, + kMaskRandom36_5, + kMaskRandom36_6, + kMaskRandom36_7, + kMaskRandom36_8, + kMaskRandom36_9, + kMaskRandom36_10, + kMaskRandom36_11, + kMaskRandom36_12, + kMaskRandom36_13, + kMaskRandom36_14, + kMaskRandom36_15, + kMaskRandom36_16, + kMaskRandom36_17, + kMaskRandom36_18, + kMaskRandom36_19, + kMaskRandom36_20, + kMaskRandom36_21, + kMaskRandom36_22, + kMaskRandom36_23, + kMaskRandom36_24, + kMaskRandom36_25, + kMaskRandom36_26, + kMaskRandom36_27, + kMaskRandom36_28, + kMaskRandom36_29, + kMaskRandom36_30, + kMaskRandom36_31, + kMaskRandom36_32, + kMaskRandom36_33, + kMaskRandom36_34, + kMaskRandom36_35, + kMaskRandom36_36 +}; + +const uint8_t* const kPacketMaskRandom37[37] = { + kMaskRandom37_1, + kMaskRandom37_2, + kMaskRandom37_3, + kMaskRandom37_4, + kMaskRandom37_5, + kMaskRandom37_6, + kMaskRandom37_7, + kMaskRandom37_8, + kMaskRandom37_9, + kMaskRandom37_10, + kMaskRandom37_11, + kMaskRandom37_12, + kMaskRandom37_13, + kMaskRandom37_14, + kMaskRandom37_15, + kMaskRandom37_16, + kMaskRandom37_17, + kMaskRandom37_18, + kMaskRandom37_19, + kMaskRandom37_20, + kMaskRandom37_21, + kMaskRandom37_22, + kMaskRandom37_23, + kMaskRandom37_24, + kMaskRandom37_25, + kMaskRandom37_26, + kMaskRandom37_27, + kMaskRandom37_28, + kMaskRandom37_29, + kMaskRandom37_30, + kMaskRandom37_31, + kMaskRandom37_32, + kMaskRandom37_33, + kMaskRandom37_34, + kMaskRandom37_35, + kMaskRandom37_36, + kMaskRandom37_37 +}; + +const uint8_t* const kPacketMaskRandom38[38] = { + kMaskRandom38_1, + kMaskRandom38_2, + kMaskRandom38_3, + kMaskRandom38_4, + kMaskRandom38_5, + kMaskRandom38_6, + kMaskRandom38_7, + kMaskRandom38_8, + kMaskRandom38_9, + kMaskRandom38_10, + kMaskRandom38_11, + kMaskRandom38_12, + kMaskRandom38_13, + kMaskRandom38_14, + kMaskRandom38_15, + kMaskRandom38_16, + kMaskRandom38_17, + kMaskRandom38_18, + kMaskRandom38_19, + kMaskRandom38_20, + kMaskRandom38_21, + kMaskRandom38_22, + kMaskRandom38_23, + kMaskRandom38_24, + kMaskRandom38_25, + kMaskRandom38_26, + kMaskRandom38_27, + kMaskRandom38_28, + kMaskRandom38_29, + kMaskRandom38_30, + kMaskRandom38_31, + kMaskRandom38_32, + kMaskRandom38_33, + kMaskRandom38_34, + kMaskRandom38_35, + kMaskRandom38_36, + kMaskRandom38_37, + kMaskRandom38_38 +}; + +const uint8_t* const kPacketMaskRandom39[39] = { + kMaskRandom39_1, + kMaskRandom39_2, + kMaskRandom39_3, + kMaskRandom39_4, + kMaskRandom39_5, + kMaskRandom39_6, + kMaskRandom39_7, + kMaskRandom39_8, + kMaskRandom39_9, + kMaskRandom39_10, + kMaskRandom39_11, + kMaskRandom39_12, + kMaskRandom39_13, + kMaskRandom39_14, + kMaskRandom39_15, + kMaskRandom39_16, + kMaskRandom39_17, + kMaskRandom39_18, + kMaskRandom39_19, + kMaskRandom39_20, + kMaskRandom39_21, + kMaskRandom39_22, + kMaskRandom39_23, + kMaskRandom39_24, + kMaskRandom39_25, + kMaskRandom39_26, + kMaskRandom39_27, + kMaskRandom39_28, + kMaskRandom39_29, + kMaskRandom39_30, + kMaskRandom39_31, + kMaskRandom39_32, + kMaskRandom39_33, + kMaskRandom39_34, + kMaskRandom39_35, + kMaskRandom39_36, + kMaskRandom39_37, + kMaskRandom39_38, + kMaskRandom39_39 +}; + +const uint8_t* const kPacketMaskRandom40[40] = { + kMaskRandom40_1, + kMaskRandom40_2, + kMaskRandom40_3, + kMaskRandom40_4, + kMaskRandom40_5, + kMaskRandom40_6, + kMaskRandom40_7, + kMaskRandom40_8, + kMaskRandom40_9, + kMaskRandom40_10, + kMaskRandom40_11, + kMaskRandom40_12, + kMaskRandom40_13, + kMaskRandom40_14, + kMaskRandom40_15, + kMaskRandom40_16, + kMaskRandom40_17, + kMaskRandom40_18, + kMaskRandom40_19, + kMaskRandom40_20, + kMaskRandom40_21, + kMaskRandom40_22, + kMaskRandom40_23, + kMaskRandom40_24, + kMaskRandom40_25, + kMaskRandom40_26, + kMaskRandom40_27, + kMaskRandom40_28, + kMaskRandom40_29, + kMaskRandom40_30, + kMaskRandom40_31, + kMaskRandom40_32, + kMaskRandom40_33, + kMaskRandom40_34, + kMaskRandom40_35, + kMaskRandom40_36, + kMaskRandom40_37, + kMaskRandom40_38, + kMaskRandom40_39, + kMaskRandom40_40 +}; + +const uint8_t* const kPacketMaskRandom41[41] = { + kMaskRandom41_1, + kMaskRandom41_2, + kMaskRandom41_3, + kMaskRandom41_4, + kMaskRandom41_5, + kMaskRandom41_6, + kMaskRandom41_7, + kMaskRandom41_8, + kMaskRandom41_9, + kMaskRandom41_10, + kMaskRandom41_11, + kMaskRandom41_12, + kMaskRandom41_13, + kMaskRandom41_14, + kMaskRandom41_15, + kMaskRandom41_16, + kMaskRandom41_17, + kMaskRandom41_18, + kMaskRandom41_19, + kMaskRandom41_20, + kMaskRandom41_21, + kMaskRandom41_22, + kMaskRandom41_23, + kMaskRandom41_24, + kMaskRandom41_25, + kMaskRandom41_26, + kMaskRandom41_27, + kMaskRandom41_28, + kMaskRandom41_29, + kMaskRandom41_30, + kMaskRandom41_31, + kMaskRandom41_32, + kMaskRandom41_33, + kMaskRandom41_34, + kMaskRandom41_35, + kMaskRandom41_36, + kMaskRandom41_37, + kMaskRandom41_38, + kMaskRandom41_39, + kMaskRandom41_40, + kMaskRandom41_41 +}; + +const uint8_t* const kPacketMaskRandom42[42] = { + kMaskRandom42_1, + kMaskRandom42_2, + kMaskRandom42_3, + kMaskRandom42_4, + kMaskRandom42_5, + kMaskRandom42_6, + kMaskRandom42_7, + kMaskRandom42_8, + kMaskRandom42_9, + kMaskRandom42_10, + kMaskRandom42_11, + kMaskRandom42_12, + kMaskRandom42_13, + kMaskRandom42_14, + kMaskRandom42_15, + kMaskRandom42_16, + kMaskRandom42_17, + kMaskRandom42_18, + kMaskRandom42_19, + kMaskRandom42_20, + kMaskRandom42_21, + kMaskRandom42_22, + kMaskRandom42_23, + kMaskRandom42_24, + kMaskRandom42_25, + kMaskRandom42_26, + kMaskRandom42_27, + kMaskRandom42_28, + kMaskRandom42_29, + kMaskRandom42_30, + kMaskRandom42_31, + kMaskRandom42_32, + kMaskRandom42_33, + kMaskRandom42_34, + kMaskRandom42_35, + kMaskRandom42_36, + kMaskRandom42_37, + kMaskRandom42_38, + kMaskRandom42_39, + kMaskRandom42_40, + kMaskRandom42_41, + kMaskRandom42_42 +}; + +const uint8_t* const kPacketMaskRandom43[43] = { + kMaskRandom43_1, + kMaskRandom43_2, + kMaskRandom43_3, + kMaskRandom43_4, + kMaskRandom43_5, + kMaskRandom43_6, + kMaskRandom43_7, + kMaskRandom43_8, + kMaskRandom43_9, + kMaskRandom43_10, + kMaskRandom43_11, + kMaskRandom43_12, + kMaskRandom43_13, + kMaskRandom43_14, + kMaskRandom43_15, + kMaskRandom43_16, + kMaskRandom43_17, + kMaskRandom43_18, + kMaskRandom43_19, + kMaskRandom43_20, + kMaskRandom43_21, + kMaskRandom43_22, + kMaskRandom43_23, + kMaskRandom43_24, + kMaskRandom43_25, + kMaskRandom43_26, + kMaskRandom43_27, + kMaskRandom43_28, + kMaskRandom43_29, + kMaskRandom43_30, + kMaskRandom43_31, + kMaskRandom43_32, + kMaskRandom43_33, + kMaskRandom43_34, + kMaskRandom43_35, + kMaskRandom43_36, + kMaskRandom43_37, + kMaskRandom43_38, + kMaskRandom43_39, + kMaskRandom43_40, + kMaskRandom43_41, + kMaskRandom43_42, + kMaskRandom43_43 +}; + +const uint8_t* const kPacketMaskRandom44[44] = { + kMaskRandom44_1, + kMaskRandom44_2, + kMaskRandom44_3, + kMaskRandom44_4, + kMaskRandom44_5, + kMaskRandom44_6, + kMaskRandom44_7, + kMaskRandom44_8, + kMaskRandom44_9, + kMaskRandom44_10, + kMaskRandom44_11, + kMaskRandom44_12, + kMaskRandom44_13, + kMaskRandom44_14, + kMaskRandom44_15, + kMaskRandom44_16, + kMaskRandom44_17, + kMaskRandom44_18, + kMaskRandom44_19, + kMaskRandom44_20, + kMaskRandom44_21, + kMaskRandom44_22, + kMaskRandom44_23, + kMaskRandom44_24, + kMaskRandom44_25, + kMaskRandom44_26, + kMaskRandom44_27, + kMaskRandom44_28, + kMaskRandom44_29, + kMaskRandom44_30, + kMaskRandom44_31, + kMaskRandom44_32, + kMaskRandom44_33, + kMaskRandom44_34, + kMaskRandom44_35, + kMaskRandom44_36, + kMaskRandom44_37, + kMaskRandom44_38, + kMaskRandom44_39, + kMaskRandom44_40, + kMaskRandom44_41, + kMaskRandom44_42, + kMaskRandom44_43, + kMaskRandom44_44 +}; + +const uint8_t* const kPacketMaskRandom45[45] = { + kMaskRandom45_1, + kMaskRandom45_2, + kMaskRandom45_3, + kMaskRandom45_4, + kMaskRandom45_5, + kMaskRandom45_6, + kMaskRandom45_7, + kMaskRandom45_8, + kMaskRandom45_9, + kMaskRandom45_10, + kMaskRandom45_11, + kMaskRandom45_12, + kMaskRandom45_13, + kMaskRandom45_14, + kMaskRandom45_15, + kMaskRandom45_16, + kMaskRandom45_17, + kMaskRandom45_18, + kMaskRandom45_19, + kMaskRandom45_20, + kMaskRandom45_21, + kMaskRandom45_22, + kMaskRandom45_23, + kMaskRandom45_24, + kMaskRandom45_25, + kMaskRandom45_26, + kMaskRandom45_27, + kMaskRandom45_28, + kMaskRandom45_29, + kMaskRandom45_30, + kMaskRandom45_31, + kMaskRandom45_32, + kMaskRandom45_33, + kMaskRandom45_34, + kMaskRandom45_35, + kMaskRandom45_36, + kMaskRandom45_37, + kMaskRandom45_38, + kMaskRandom45_39, + kMaskRandom45_40, + kMaskRandom45_41, + kMaskRandom45_42, + kMaskRandom45_43, + kMaskRandom45_44, + kMaskRandom45_45 +}; + +const uint8_t* const kPacketMaskRandom46[46] = { + kMaskRandom46_1, + kMaskRandom46_2, + kMaskRandom46_3, + kMaskRandom46_4, + kMaskRandom46_5, + kMaskRandom46_6, + kMaskRandom46_7, + kMaskRandom46_8, + kMaskRandom46_9, + kMaskRandom46_10, + kMaskRandom46_11, + kMaskRandom46_12, + kMaskRandom46_13, + kMaskRandom46_14, + kMaskRandom46_15, + kMaskRandom46_16, + kMaskRandom46_17, + kMaskRandom46_18, + kMaskRandom46_19, + kMaskRandom46_20, + kMaskRandom46_21, + kMaskRandom46_22, + kMaskRandom46_23, + kMaskRandom46_24, + kMaskRandom46_25, + kMaskRandom46_26, + kMaskRandom46_27, + kMaskRandom46_28, + kMaskRandom46_29, + kMaskRandom46_30, + kMaskRandom46_31, + kMaskRandom46_32, + kMaskRandom46_33, + kMaskRandom46_34, + kMaskRandom46_35, + kMaskRandom46_36, + kMaskRandom46_37, + kMaskRandom46_38, + kMaskRandom46_39, + kMaskRandom46_40, + kMaskRandom46_41, + kMaskRandom46_42, + kMaskRandom46_43, + kMaskRandom46_44, + kMaskRandom46_45, + kMaskRandom46_46 +}; + +const uint8_t* const kPacketMaskRandom47[47] = { + kMaskRandom47_1, + kMaskRandom47_2, + kMaskRandom47_3, + kMaskRandom47_4, + kMaskRandom47_5, + kMaskRandom47_6, + kMaskRandom47_7, + kMaskRandom47_8, + kMaskRandom47_9, + kMaskRandom47_10, + kMaskRandom47_11, + kMaskRandom47_12, + kMaskRandom47_13, + kMaskRandom47_14, + kMaskRandom47_15, + kMaskRandom47_16, + kMaskRandom47_17, + kMaskRandom47_18, + kMaskRandom47_19, + kMaskRandom47_20, + kMaskRandom47_21, + kMaskRandom47_22, + kMaskRandom47_23, + kMaskRandom47_24, + kMaskRandom47_25, + kMaskRandom47_26, + kMaskRandom47_27, + kMaskRandom47_28, + kMaskRandom47_29, + kMaskRandom47_30, + kMaskRandom47_31, + kMaskRandom47_32, + kMaskRandom47_33, + kMaskRandom47_34, + kMaskRandom47_35, + kMaskRandom47_36, + kMaskRandom47_37, + kMaskRandom47_38, + kMaskRandom47_39, + kMaskRandom47_40, + kMaskRandom47_41, + kMaskRandom47_42, + kMaskRandom47_43, + kMaskRandom47_44, + kMaskRandom47_45, + kMaskRandom47_46, + kMaskRandom47_47 +}; + +const uint8_t* const kPacketMaskRandom48[48] = { + kMaskRandom48_1, + kMaskRandom48_2, + kMaskRandom48_3, + kMaskRandom48_4, + kMaskRandom48_5, + kMaskRandom48_6, + kMaskRandom48_7, + kMaskRandom48_8, + kMaskRandom48_9, + kMaskRandom48_10, + kMaskRandom48_11, + kMaskRandom48_12, + kMaskRandom48_13, + kMaskRandom48_14, + kMaskRandom48_15, + kMaskRandom48_16, + kMaskRandom48_17, + kMaskRandom48_18, + kMaskRandom48_19, + kMaskRandom48_20, + kMaskRandom48_21, + kMaskRandom48_22, + kMaskRandom48_23, + kMaskRandom48_24, + kMaskRandom48_25, + kMaskRandom48_26, + kMaskRandom48_27, + kMaskRandom48_28, + kMaskRandom48_29, + kMaskRandom48_30, + kMaskRandom48_31, + kMaskRandom48_32, + kMaskRandom48_33, + kMaskRandom48_34, + kMaskRandom48_35, + kMaskRandom48_36, + kMaskRandom48_37, + kMaskRandom48_38, + kMaskRandom48_39, + kMaskRandom48_40, + kMaskRandom48_41, + kMaskRandom48_42, + kMaskRandom48_43, + kMaskRandom48_44, + kMaskRandom48_45, + kMaskRandom48_46, + kMaskRandom48_47, + kMaskRandom48_48 +}; + +const uint8_t* const* const kPacketMaskRandomTbl[48] = { + kPacketMaskRandom1, + kPacketMaskRandom2, + kPacketMaskRandom3, + kPacketMaskRandom4, + kPacketMaskRandom5, + kPacketMaskRandom6, + kPacketMaskRandom7, + kPacketMaskRandom8, + kPacketMaskRandom9, + kPacketMaskRandom10, + kPacketMaskRandom11, + kPacketMaskRandom12, + kPacketMaskRandom13, + kPacketMaskRandom14, + kPacketMaskRandom15, + kPacketMaskRandom16, + kPacketMaskRandom17, + kPacketMaskRandom18, + kPacketMaskRandom19, + kPacketMaskRandom20, + kPacketMaskRandom21, + kPacketMaskRandom22, + kPacketMaskRandom23, + kPacketMaskRandom24, + kPacketMaskRandom25, + kPacketMaskRandom26, + kPacketMaskRandom27, + kPacketMaskRandom28, + kPacketMaskRandom29, + kPacketMaskRandom30, + kPacketMaskRandom31, + kPacketMaskRandom32, + kPacketMaskRandom33, + kPacketMaskRandom34, + kPacketMaskRandom35, + kPacketMaskRandom36, + kPacketMaskRandom37, + kPacketMaskRandom38, + kPacketMaskRandom39, + kPacketMaskRandom40, + kPacketMaskRandom41, + kPacketMaskRandom42, + kPacketMaskRandom43, + kPacketMaskRandom44, + kPacketMaskRandom45, + kPacketMaskRandom46, + kPacketMaskRandom47, + kPacketMaskRandom48 +}; + +} // namespace fec_private_tables +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_RANDOM_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.cc new file mode 100644 index 0000000000..d73af5a31c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.cc @@ -0,0 +1,217 @@ +/* + * 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 "modules/rtp_rtcp/source/fec_test_helper.h" + +#include <memory> +#include <utility> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace test { +namespace fec { + +namespace { +constexpr uint8_t kFecPayloadType = 96; +constexpr uint8_t kRedPayloadType = 97; +constexpr uint8_t kVp8PayloadType = 120; + +constexpr int kPacketTimestampIncrement = 3000; +} // namespace + +ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( + int num_media_packets, + uint16_t start_seq_num) { + RTC_DCHECK_GT(num_media_packets, 0); + uint16_t seq_num = start_seq_num; + int time_stamp = random_->Rand<int>(); + + ForwardErrorCorrection::PacketList media_packets; + + for (int i = 0; i < num_media_packets; ++i) { + std::unique_ptr<ForwardErrorCorrection::Packet> media_packet( + new ForwardErrorCorrection::Packet()); + media_packet->length = random_->Rand(min_packet_size_, max_packet_size_); + + // Generate random values for the first 2 bytes + media_packet->data[0] = random_->Rand<uint8_t>(); + media_packet->data[1] = random_->Rand<uint8_t>(); + + // The first two bits are assumed to be 10 by the FEC encoder. + // In fact the FEC decoder will set the two first bits to 10 regardless of + // what they actually were. Set the first two bits to 10 so that a memcmp + // can be performed for the whole restored packet. + media_packet->data[0] |= 0x80; + media_packet->data[0] &= 0xbf; + + // FEC is applied to a whole frame. + // A frame is signaled by multiple packets without the marker bit set + // followed by the last packet of the frame for which the marker bit is set. + // Only push one (fake) frame to the FEC. + media_packet->data[1] &= 0x7f; + + webrtc::ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2], + seq_num); + webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4], + time_stamp); + webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], ssrc_); + + // Generate random values for payload. + for (size_t j = 12; j < media_packet->length; ++j) + media_packet->data[j] = random_->Rand<uint8_t>(); + seq_num++; + media_packets.push_back(std::move(media_packet)); + } + // Last packet, set marker bit. + ForwardErrorCorrection::Packet* media_packet = media_packets.back().get(); + RTC_DCHECK(media_packet); + media_packet->data[1] |= 0x80; + + next_seq_num_ = seq_num; + + return media_packets; +} + +ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( + int num_media_packets) { + return ConstructMediaPackets(num_media_packets, random_->Rand<uint16_t>()); +} + +uint16_t MediaPacketGenerator::GetNextSeqNum() { + return next_seq_num_; +} + +AugmentedPacketGenerator::AugmentedPacketGenerator(uint32_t ssrc) + : num_packets_(0), ssrc_(ssrc), seq_num_(0), timestamp_(0) {} + +void AugmentedPacketGenerator::NewFrame(size_t num_packets) { + num_packets_ = num_packets; + timestamp_ += kPacketTimestampIncrement; +} + +uint16_t AugmentedPacketGenerator::NextPacketSeqNum() { + return ++seq_num_; +} + +std::unique_ptr<AugmentedPacket> AugmentedPacketGenerator::NextPacket( + size_t offset, + size_t length) { + std::unique_ptr<AugmentedPacket> packet(new AugmentedPacket()); + + for (size_t i = 0; i < length; ++i) + packet->data[i + kRtpHeaderSize] = offset + i; + packet->length = length + kRtpHeaderSize; + memset(&packet->header, 0, sizeof(WebRtcRTPHeader)); + packet->header.frameType = kVideoFrameDelta; + packet->header.header.headerLength = kRtpHeaderSize; + packet->header.header.markerBit = (num_packets_ == 1); + packet->header.header.payloadType = kVp8PayloadType; + packet->header.header.sequenceNumber = seq_num_; + packet->header.header.timestamp = timestamp_; + packet->header.header.ssrc = ssrc_; + WriteRtpHeader(packet->header.header, packet->data); + ++seq_num_; + --num_packets_; + + return packet; +} + +void AugmentedPacketGenerator::WriteRtpHeader(const RTPHeader& header, + uint8_t* data) { + data[0] = 0x80; // Version 2. + data[1] = header.payloadType; + data[1] |= (header.markerBit ? kRtpMarkerBitMask : 0); + ByteWriter<uint16_t>::WriteBigEndian(data + 2, header.sequenceNumber); + ByteWriter<uint32_t>::WriteBigEndian(data + 4, header.timestamp); + ByteWriter<uint32_t>::WriteBigEndian(data + 8, header.ssrc); +} + +FlexfecPacketGenerator::FlexfecPacketGenerator(uint32_t media_ssrc, + uint32_t flexfec_ssrc) + : AugmentedPacketGenerator(media_ssrc), + flexfec_ssrc_(flexfec_ssrc), + flexfec_seq_num_(0), + flexfec_timestamp_(0) {} + +std::unique_ptr<AugmentedPacket> FlexfecPacketGenerator::BuildFlexfecPacket( + const ForwardErrorCorrection::Packet& packet) { + RTC_DCHECK_LE(packet.length, + static_cast<size_t>(IP_PACKET_SIZE - kRtpHeaderSize)); + + RTPHeader header; + header.sequenceNumber = flexfec_seq_num_; + ++flexfec_seq_num_; + header.timestamp = flexfec_timestamp_; + flexfec_timestamp_ += kPacketTimestampIncrement; + header.ssrc = flexfec_ssrc_; + + std::unique_ptr<AugmentedPacket> packet_with_rtp_header( + new AugmentedPacket()); + WriteRtpHeader(header, packet_with_rtp_header->data); + memcpy(packet_with_rtp_header->data + kRtpHeaderSize, packet.data, + packet.length); + packet_with_rtp_header->length = kRtpHeaderSize + packet.length; + + return packet_with_rtp_header; +} + +UlpfecPacketGenerator::UlpfecPacketGenerator(uint32_t ssrc) + : AugmentedPacketGenerator(ssrc) {} + +std::unique_ptr<AugmentedPacket> UlpfecPacketGenerator::BuildMediaRedPacket( + const AugmentedPacket& packet) { + std::unique_ptr<AugmentedPacket> red_packet(new AugmentedPacket()); + + const size_t kHeaderLength = packet.header.header.headerLength; + red_packet->header = packet.header; + red_packet->length = packet.length + 1; // 1 byte RED header. + // Copy RTP header. + memcpy(red_packet->data, packet.data, kHeaderLength); + SetRedHeader(red_packet->data[1] & 0x7f, kHeaderLength, red_packet.get()); + memcpy(red_packet->data + kHeaderLength + 1, packet.data + kHeaderLength, + packet.length - kHeaderLength); + + return red_packet; +} + +std::unique_ptr<AugmentedPacket> UlpfecPacketGenerator::BuildUlpfecRedPacket( + const ForwardErrorCorrection::Packet& packet) { + // Create a fake media packet to get a correct header. 1 byte RED header. + ++num_packets_; + std::unique_ptr<AugmentedPacket> red_packet = + NextPacket(0, packet.length + 1); + + red_packet->data[1] &= ~0x80; // Clear marker bit. + const size_t kHeaderLength = red_packet->header.header.headerLength; + SetRedHeader(kFecPayloadType, kHeaderLength, red_packet.get()); + memcpy(red_packet->data + kHeaderLength + 1, packet.data, packet.length); + red_packet->length = kHeaderLength + 1 + packet.length; + + return red_packet; +} + +void UlpfecPacketGenerator::SetRedHeader(uint8_t payload_type, + size_t header_length, + AugmentedPacket* red_packet) { + // Replace payload type. + red_packet->data[1] &= 0x80; // Reset. + red_packet->data[1] += kRedPayloadType; // Replace. + + // Add RED header, f-bit always 0. + red_packet->data[header_length] = payload_type; +} + +} // namespace fec +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.h new file mode 100644 index 0000000000..712b20143b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.h @@ -0,0 +1,134 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_ +#define MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_ + +#include <memory> + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/random.h" + +namespace webrtc { +namespace test { +namespace fec { + +struct AugmentedPacket : public ForwardErrorCorrection::Packet { + WebRtcRTPHeader header; +}; + +// TODO(brandtr): Consider merging MediaPacketGenerator and +// AugmentedPacketGenerator into a single class, since their functionality is +// similar. + +// This class generates media packets corresponding to a single frame. +class MediaPacketGenerator { + public: + MediaPacketGenerator(uint32_t min_packet_size, + uint32_t max_packet_size, + uint32_t ssrc, + Random* random) + : min_packet_size_(min_packet_size), + max_packet_size_(max_packet_size), + ssrc_(ssrc), + random_(random) {} + + // Construct the media packets, up to |num_media_packets| packets. + ForwardErrorCorrection::PacketList ConstructMediaPackets( + int num_media_packets, + uint16_t start_seq_num); + ForwardErrorCorrection::PacketList ConstructMediaPackets( + int num_media_packets); + + uint16_t GetNextSeqNum(); + + private: + uint32_t min_packet_size_; + uint32_t max_packet_size_; + uint32_t ssrc_; + Random* random_; + + ForwardErrorCorrection::PacketList media_packets_; + uint16_t next_seq_num_; +}; + +// This class generates media packets with a certain structure of the payload. +class AugmentedPacketGenerator { + public: + explicit AugmentedPacketGenerator(uint32_t ssrc); + + // Prepare for generating a new set of packets, corresponding to a frame. + void NewFrame(size_t num_packets); + + // Increment and return the newly incremented sequence number. + uint16_t NextPacketSeqNum(); + + // Return the next packet in the current frame. + std::unique_ptr<AugmentedPacket> NextPacket(size_t offset, size_t length); + + protected: + // Given |header|, writes the appropriate RTP header fields in |data|. + static void WriteRtpHeader(const RTPHeader& header, uint8_t* data); + + // Number of packets left to generate, in the current frame. + size_t num_packets_; + + private: + uint32_t ssrc_; + uint16_t seq_num_; + uint32_t timestamp_; +}; + +// This class generates media and FlexFEC packets for a single frame. +class FlexfecPacketGenerator : public AugmentedPacketGenerator { + public: + FlexfecPacketGenerator(uint32_t media_ssrc, uint32_t flexfec_ssrc); + + // Creates a new AugmentedPacket (with RTP headers) from a + // FlexFEC packet (without RTP headers). + std::unique_ptr<AugmentedPacket> BuildFlexfecPacket( + const ForwardErrorCorrection::Packet& packet); + + private: + uint32_t flexfec_ssrc_; + uint16_t flexfec_seq_num_; + uint32_t flexfec_timestamp_; +}; + +// This class generates media and ULPFEC packets (both encapsulated in RED) +// for a single frame. +class UlpfecPacketGenerator : public AugmentedPacketGenerator { + public: + explicit UlpfecPacketGenerator(uint32_t ssrc); + + // Creates a new AugmentedPacket with the RED header added to the packet. + static std::unique_ptr<AugmentedPacket> BuildMediaRedPacket( + const AugmentedPacket& packet); + + // Creates a new AugmentedPacket with FEC payload and RED header. Does this by + // creating a new fake media AugmentedPacket, clears the marker bit and adds a + // RED header. Finally replaces the payload with the content of + // |packet->data|. + std::unique_ptr<AugmentedPacket> BuildUlpfecRedPacket( + const ForwardErrorCorrection::Packet& packet); + + private: + static void SetRedHeader(uint8_t payload_type, + size_t header_length, + AugmentedPacket* red_packet); +}; + +} // namespace fec +} // namespace test +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc new file mode 100644 index 0000000000..d7666e1192 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/flexfec_header_reader_writer.h" + +#include <string.h> + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +namespace { + +// Maximum number of media packets that can be protected in one batch. +constexpr size_t kMaxMediaPackets = 48; // Since we are reusing ULPFEC masks. + +// Maximum number of FEC packets stored inside ForwardErrorCorrection. +constexpr size_t kMaxFecPackets = kMaxMediaPackets; + +// Size (in bytes) of packet masks, given number of K bits set. +constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14}; + +// Size (in bytes) of part of header which is not packet mask specific. +constexpr size_t kBaseHeaderSize = 12; + +// Size (in bytes) of part of header which is stream specific. +constexpr size_t kStreamSpecificHeaderSize = 6; + +// Size (in bytes) of header, given the single stream packet mask size, i.e. +// the number of K-bits set. +constexpr size_t kHeaderSizes[] = { + kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[0], + kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1], + kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]}; + +// We currently only support single-stream protection. +// TODO(brandtr): Update this when we support multistream protection. +constexpr uint8_t kSsrcCount = 1; + +// There are three reserved bytes that MUST be set to zero in the header. +constexpr uint32_t kReservedBits = 0; + +// TODO(brandtr): Update this when we support multistream protection. +constexpr size_t kPacketMaskOffset = + kBaseHeaderSize + kStreamSpecificHeaderSize; + +// Here we count the K-bits as belonging to the packet mask. +// This can be used in conjunction with FlexfecHeaderWriter::MinPacketMaskSize, +// which calculates a bound on the needed packet mask size including K-bits, +// given a packet mask without K-bits. +size_t FlexfecHeaderSize(size_t packet_mask_size) { + RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]); + if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) { + return kHeaderSizes[0]; + } else if (packet_mask_size <= kFlexfecPacketMaskSizes[1]) { + return kHeaderSizes[1]; + } + return kHeaderSizes[2]; +} + +} // namespace + +FlexfecHeaderReader::FlexfecHeaderReader() + : FecHeaderReader(kMaxMediaPackets, kMaxFecPackets) {} + +FlexfecHeaderReader::~FlexfecHeaderReader() = default; + +// TODO(brandtr): Update this function when we support flexible masks, +// retransmissions, and/or several protected SSRCs. +bool FlexfecHeaderReader::ReadFecHeader( + ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const { + if (fec_packet->pkt->length <= kBaseHeaderSize + kStreamSpecificHeaderSize) { + RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; + return false; + } + bool r_bit = (fec_packet->pkt->data[0] & 0x80) != 0; + if (r_bit) { + RTC_LOG(LS_INFO) + << "FlexFEC packet with retransmission bit set. We do not yet " + "support this, thus discarding the packet."; + return false; + } + bool f_bit = (fec_packet->pkt->data[0] & 0x40) != 0; + if (f_bit) { + RTC_LOG(LS_INFO) + << "FlexFEC packet with inflexible generator matrix. We do " + "not yet support this, thus discarding packet."; + return false; + } + uint8_t ssrc_count = + ByteReader<uint8_t>::ReadBigEndian(&fec_packet->pkt->data[8]); + if (ssrc_count != 1) { + RTC_LOG(LS_INFO) + << "FlexFEC packet protecting multiple media SSRCs. We do not " + "yet support this, thus discarding packet."; + return false; + } + uint32_t protected_ssrc = + ByteReader<uint32_t>::ReadBigEndian(&fec_packet->pkt->data[12]); + uint16_t seq_num_base = + ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[16]); + + // Parse the FlexFEC packet mask and remove the interleaved K-bits. + // (See FEC header schematic in flexfec_header_reader_writer.h.) + // We store the packed packet mask in-band, which "destroys" the standards + // compliance of the header. That is fine though, since the code that + // reads from the header (from this point and onwards) is aware of this. + // TODO(brandtr): When the FEC packet classes have been refactored, store + // the packed packet masks out-of-band, thus leaving the FlexFEC header as is. + // + // We treat the mask parts as unsigned integers with host order endianness + // in order to simplify the bit shifting between bytes. + if (fec_packet->pkt->length < kHeaderSizes[0]) { + RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; + return false; + } + uint8_t* const packet_mask = fec_packet->pkt->data + kPacketMaskOffset; + bool k_bit0 = (packet_mask[0] & 0x80) != 0; + uint16_t mask_part0 = ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]); + // Shift away K-bit 0, implicitly clearing the last bit. + mask_part0 <<= 1; + ByteWriter<uint16_t>::WriteBigEndian(&packet_mask[0], mask_part0); + size_t packet_mask_size; + if (k_bit0) { + // The first K-bit is set, and the packet mask is thus only 2 bytes long. + // We have now read the entire FEC header, and the rest of the packet + // is payload. + packet_mask_size = kFlexfecPacketMaskSizes[0]; + } else { + if (fec_packet->pkt->length < kHeaderSizes[1]) { + return false; + } + bool k_bit1 = (packet_mask[2] & 0x80) != 0; + // We have already shifted the first two bytes of the packet mask one step + // to the left, thus removing K-bit 0. We will now shift the next four bytes + // of the packet mask two steps to the left. (One step for the removed + // K-bit 0, and one step for the to be removed K-bit 1). + uint8_t bit15 = (packet_mask[2] >> 6) & 0x01; + packet_mask[1] |= bit15; + uint32_t mask_part1 = ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]); + // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits. + mask_part1 <<= 2; + ByteWriter<uint32_t>::WriteBigEndian(&packet_mask[2], mask_part1); + if (k_bit1) { + // The first K-bit is clear, but the second K-bit is set. The packet + // mask is thus 6 bytes long. We have now read the entire FEC header, + // and the rest of the packet is payload. + packet_mask_size = kFlexfecPacketMaskSizes[1]; + } else { + if (fec_packet->pkt->length < kHeaderSizes[2]) { + RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet."; + return false; + } + bool k_bit2 = (packet_mask[6] & 0x80) != 0; + if (k_bit2) { + // The first and second K-bits are clear, but the third K-bit is set. + // The packet mask is thus 14 bytes long. We have now read the entire + // FEC header, and the rest of the packet is payload. + packet_mask_size = kFlexfecPacketMaskSizes[2]; + } else { + RTC_LOG(LS_WARNING) + << "Discarding FlexFEC packet with malformed header."; + return false; + } + // At this point, K-bits 0 and 1 have been removed, and the front-most + // part of the FlexFEC packet mask has been packed accordingly. We will + // now shift the remaning part of the packet mask three steps to the left. + // This corresponds to the (in total) three K-bits, which have been + // removed. + uint8_t tail_bits = (packet_mask[6] >> 5) & 0x03; + packet_mask[5] |= tail_bits; + uint64_t mask_part2 = + ByteReader<uint64_t>::ReadBigEndian(&packet_mask[6]); + // Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last + // three bits. + mask_part2 <<= 3; + ByteWriter<uint64_t>::WriteBigEndian(&packet_mask[6], mask_part2); + } + } + + // Store "ULPFECized" packet mask info. + fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size); + fec_packet->protected_ssrc = protected_ssrc; + fec_packet->seq_num_base = seq_num_base; + fec_packet->packet_mask_offset = kPacketMaskOffset; + fec_packet->packet_mask_size = packet_mask_size; + + // In FlexFEC, all media packets are protected in their entirety. + fec_packet->protection_length = + fec_packet->pkt->length - fec_packet->fec_header_size; + + return true; +} + +FlexfecHeaderWriter::FlexfecHeaderWriter() + : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {} + +FlexfecHeaderWriter::~FlexfecHeaderWriter() = default; + +size_t FlexfecHeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask, + size_t packet_mask_size) const { + if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear && + (packet_mask[1] & 0x01) == 0) { + // Packet mask is 16 bits long, with bit 15 clear. + // It can be used as is. + return kFlexfecPacketMaskSizes[0]; + } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) { + // Packet mask is 16 bits long, with bit 15 set. + // We must expand the packet mask with zeros in the FlexFEC header. + return kFlexfecPacketMaskSizes[1]; + } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet && + (packet_mask[5] & 0x03) == 0) { + // Packet mask is 48 bits long, with bits 46 and 47 clear. + // It can be used as is. + return kFlexfecPacketMaskSizes[1]; + } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) { + // Packet mask is 48 bits long, with at least one of bits 46 and 47 set. + // We must expand it with zeros. + return kFlexfecPacketMaskSizes[2]; + } + RTC_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size << "."; + return kFlexfecPacketMaskSizes[2]; +} + +size_t FlexfecHeaderWriter::FecHeaderSize(size_t packet_mask_size) const { + return FlexfecHeaderSize(packet_mask_size); +} + +// This function adapts the precomputed ULPFEC packet masks to the +// FlexFEC header standard. Note that the header size is computed by +// FecHeaderSize(), so in this function we can be sure that we are +// writing in space that is intended for the header. +// +// TODO(brandtr): Update this function when we support offset-based masks, +// retransmissions, and protecting multiple SSRCs. +void FlexfecHeaderWriter::FinalizeFecHeader( + uint32_t media_ssrc, + uint16_t seq_num_base, + const uint8_t* packet_mask, + size_t packet_mask_size, + ForwardErrorCorrection::Packet* fec_packet) const { + fec_packet->data[0] &= 0x7f; // Clear R bit. + fec_packet->data[0] &= 0xbf; // Clear F bit. + ByteWriter<uint8_t>::WriteBigEndian(&fec_packet->data[8], kSsrcCount); + ByteWriter<uint32_t, 3>::WriteBigEndian(&fec_packet->data[9], kReservedBits); + ByteWriter<uint32_t>::WriteBigEndian(&fec_packet->data[12], media_ssrc); + ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[16], seq_num_base); + // Adapt ULPFEC packet mask to FlexFEC header. + // + // We treat the mask parts as unsigned integers with host order endianness + // in order to simplify the bit shifting between bytes. + uint8_t* const written_packet_mask = fec_packet->data + kPacketMaskOffset; + if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) { + // The packet mask is 48 bits long. + uint16_t tmp_mask_part0 = + ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]); + uint32_t tmp_mask_part1 = + ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]); + + tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0. + ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0], + tmp_mask_part0); + tmp_mask_part1 >>= 2; // Shift, thus clearing K-bit 1 and bit 15. + ByteWriter<uint32_t>::WriteBigEndian(&written_packet_mask[2], + tmp_mask_part1); + bool bit15 = (packet_mask[1] & 0x01) != 0; + if (bit15) + written_packet_mask[2] |= 0x40; // Set bit 15. + bool bit46 = (packet_mask[5] & 0x02) != 0; + bool bit47 = (packet_mask[5] & 0x01) != 0; + if (!bit46 && !bit47) { + written_packet_mask[2] |= 0x80; // Set K-bit 1. + } else { + memset(&written_packet_mask[6], 0, 8); // Clear all trailing bits. + written_packet_mask[6] |= 0x80; // Set K-bit 2. + if (bit46) + written_packet_mask[6] |= 0x40; // Set bit 46. + if (bit47) + written_packet_mask[6] |= 0x20; // Set bit 47. + } + } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) { + // The packet mask is 16 bits long. + uint16_t tmp_mask_part0 = + ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]); + + tmp_mask_part0 >>= 1; // Shift, thus clearing K-bit 0. + ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0], + tmp_mask_part0); + bool bit15 = (packet_mask[1] & 0x01) != 0; + if (!bit15) { + written_packet_mask[0] |= 0x80; // Set K-bit 0. + } else { + memset(&written_packet_mask[2], 0U, 4); // Clear all trailing bits. + written_packet_mask[2] |= 0x80; // Set K-bit 1. + written_packet_mask[2] |= 0x40; // Set bit 15. + } + } else { + RTC_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size + << "."; + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.h new file mode 100644 index 0000000000..3bb73f97bc --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER_H_ +#define MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER_H_ + +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { + +// FlexFEC header, minimum 20 bytes. +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 |R|F|P|X| CC |M| PT recovery | length recovery | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | TS recovery | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | SSRCCount | reserved | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// 12 | SSRC_i | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | SN base_i |k| Mask [0-14] | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 20 |k| Mask [15-45] (optional) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 24 |k| | +// +-+ Mask [46-108] (optional) | +// 28 | | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// : ... next in SSRC_i ... : +// +// +// FlexFEC header in 'inflexible' mode (F = 1), 20 bytes. +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 |0|1|P|X| CC |M| PT recovery | length recovery | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | TS recovery | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | SSRCCount | reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | SSRC_i | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | SN base_i | M (columns) | N (rows) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +class FlexfecHeaderReader : public FecHeaderReader { + public: + FlexfecHeaderReader(); + ~FlexfecHeaderReader() override; + + bool ReadFecHeader( + ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override; +}; + +class FlexfecHeaderWriter : public FecHeaderWriter { + public: + FlexfecHeaderWriter(); + ~FlexfecHeaderWriter() override; + + size_t MinPacketMaskSize(const uint8_t* packet_mask, + size_t packet_mask_size) const override; + + size_t FecHeaderSize(size_t packet_mask_row_size) const override; + + void FinalizeFecHeader( + uint32_t media_ssrc, + uint16_t seq_num_base, + const uint8_t* packet_mask, + size_t packet_mask_size, + ForwardErrorCorrection::Packet* fec_packet) const override; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc new file mode 100644 index 0000000000..0f0bf274fa --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2016 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 <string.h> + +#include <memory> +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/checks.h" +#include "rtc_base/random.h" +#include "rtc_base/scoped_ref_ptr.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +using Packet = ForwardErrorCorrection::Packet; +using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket; + +// General. Assume single-stream protection. +constexpr uint32_t kMediaSsrc = 1254983; +constexpr uint16_t kMediaStartSeqNum = 825; +constexpr size_t kMediaPacketLength = 1234; +constexpr uint32_t kFlexfecSsrc = 52142; + +constexpr size_t kFlexfecHeaderSizes[] = {20, 24, 32}; +constexpr size_t kFlexfecPacketMaskOffset = 18; +constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14}; +constexpr size_t kFlexfecMaxPacketSize = kFlexfecPacketMaskSizes[2]; + +// Reader tests. +constexpr uint8_t kNoRBit = 0 << 7; +constexpr uint8_t kNoFBit = 0 << 6; +constexpr uint8_t kPtRecovery = 123; +constexpr uint8_t kLengthRecov[] = {0xab, 0xcd}; +constexpr uint8_t kTsRecovery[] = {0x01, 0x23, 0x45, 0x67}; +constexpr uint8_t kSsrcCount = 1; +constexpr uint8_t kReservedBits = 0x00; +constexpr uint8_t kProtSsrc[] = {0x11, 0x22, 0x33, 0x44}; +constexpr uint8_t kSnBase[] = {0xaa, 0xbb}; +constexpr uint8_t kPayloadBits = 0x00; + +std::unique_ptr<uint8_t[]> GeneratePacketMask(size_t packet_mask_size, + uint64_t seed) { + Random random(seed); + std::unique_ptr<uint8_t[]> packet_mask(new uint8_t[kFlexfecMaxPacketSize]); + memset(packet_mask.get(), 0, kFlexfecMaxPacketSize); + for (size_t i = 0; i < packet_mask_size; ++i) { + packet_mask[i] = random.Rand<uint8_t>(); + } + return packet_mask; +} + +void ClearBit(size_t index, uint8_t* packet_mask) { + packet_mask[index / 8] &= ~(1 << (7 - index % 8)); +} + +void SetBit(size_t index, uint8_t* packet_mask) { + packet_mask[index / 8] |= (1 << (7 - index % 8)); +} + +rtc::scoped_refptr<Packet> WriteHeader(const uint8_t* packet_mask, + size_t packet_mask_size) { + FlexfecHeaderWriter writer; + rtc::scoped_refptr<Packet> written_packet(new Packet()); + written_packet->length = kMediaPacketLength; + for (size_t i = 0; i < written_packet->length; ++i) { + written_packet->data[i] = i; // Actual content doesn't matter. + } + writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask, + packet_mask_size, written_packet.get()); + return written_packet; +} + +std::unique_ptr<ReceivedFecPacket> ReadHeader(const Packet& written_packet) { + FlexfecHeaderReader reader; + std::unique_ptr<ReceivedFecPacket> read_packet(new ReceivedFecPacket()); + read_packet->ssrc = kFlexfecSsrc; + read_packet->pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(read_packet->pkt->data, written_packet.data, written_packet.length); + read_packet->pkt->length = written_packet.length; + EXPECT_TRUE(reader.ReadFecHeader(read_packet.get())); + return read_packet; +} + +void VerifyReadHeaders(size_t expected_fec_header_size, + const uint8_t* expected_packet_mask, + size_t expected_packet_mask_size, + const ReceivedFecPacket& read_packet) { + EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size); + EXPECT_EQ(ByteReader<uint32_t>::ReadBigEndian(kProtSsrc), + read_packet.protected_ssrc); + EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(kSnBase), + read_packet.seq_num_base); + const size_t packet_mask_offset = read_packet.packet_mask_offset; + EXPECT_EQ(kFlexfecPacketMaskOffset, packet_mask_offset); + EXPECT_EQ(expected_packet_mask_size, read_packet.packet_mask_size); + EXPECT_EQ(read_packet.pkt->length - expected_fec_header_size, + read_packet.protection_length); + // Ensure that the K-bits are removed and the packet mask has been packed. + EXPECT_THAT(::testing::make_tuple(read_packet.pkt->data + packet_mask_offset, + read_packet.packet_mask_size), + ::testing::ElementsAreArray(expected_packet_mask, + expected_packet_mask_size)); +} + +void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask, + size_t expected_packet_mask_size, + const Packet& written_packet) { + const uint8_t* packet = written_packet.data; + EXPECT_EQ(0x00, packet[0] & 0x80); // F bit clear. + EXPECT_EQ(0x00, packet[0] & 0x40); // R bit clear. + EXPECT_EQ(0x01, packet[8]); // SSRCCount = 1. + EXPECT_EQ(kMediaSsrc, ByteReader<uint32_t>::ReadBigEndian(packet + 12)); + EXPECT_EQ(kMediaStartSeqNum, + ByteReader<uint16_t>::ReadBigEndian(packet + 16)); + EXPECT_THAT(::testing::make_tuple(packet + kFlexfecPacketMaskOffset, + expected_packet_mask_size), + ::testing::ElementsAreArray(expected_packet_mask, + expected_packet_mask_size)); +} + +void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size, + const uint8_t* expected_packet_mask, + size_t expected_packet_mask_size, + const Packet& written_packet, + const ReceivedFecPacket& read_packet) { + EXPECT_EQ(kFlexfecSsrc, read_packet.ssrc); + EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size); + EXPECT_EQ(kMediaSsrc, read_packet.protected_ssrc); + EXPECT_EQ(kMediaStartSeqNum, read_packet.seq_num_base); + EXPECT_EQ(kFlexfecPacketMaskOffset, read_packet.packet_mask_offset); + ASSERT_EQ(expected_packet_mask_size, read_packet.packet_mask_size); + EXPECT_EQ(written_packet.length - expected_fec_header_size, + read_packet.protection_length); + // Verify that the call to ReadFecHeader did normalize the packet masks. + EXPECT_THAT( + ::testing::make_tuple(read_packet.pkt->data + kFlexfecPacketMaskOffset, + read_packet.packet_mask_size), + ::testing::ElementsAreArray(expected_packet_mask, + expected_packet_mask_size)); + // Verify that the call to ReadFecHeader did not tamper with the payload. + EXPECT_THAT(::testing::make_tuple( + read_packet.pkt->data + read_packet.fec_header_size, + read_packet.pkt->length - read_packet.fec_header_size), + ::testing::ElementsAreArray( + written_packet.data + expected_fec_header_size, + written_packet.length - expected_fec_header_size)); +} + +} // namespace + +TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0Set) { + constexpr uint8_t kKBit0 = 1 << 7; + constexpr size_t kExpectedPacketMaskSize = 2; + constexpr size_t kExpectedFecHeaderSize = 20; + // clang-format off + constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81}; + constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02}; + // clang-format on + constexpr uint8_t kPacketData[] = { + kNoRBit | kNoFBit, kPtRecovery, kLengthRecov[0], kLengthRecov[1], + kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3], + kSsrcCount, kReservedBits, kReservedBits, kReservedBits, + kProtSsrc[0], kProtSsrc[1], kProtSsrc[2], kProtSsrc[3], + kSnBase[0], kSnBase[1], kFlexfecPktMask[0], kFlexfecPktMask[1], + kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits}; + const size_t packet_length = sizeof(kPacketData); + ReceivedFecPacket read_packet; + read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(read_packet.pkt->data, kPacketData, packet_length); + read_packet.pkt->length = packet_length; + + FlexfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask, + kExpectedPacketMaskSize, read_packet); +} + +TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1Set) { + constexpr uint8_t kKBit0 = 0 << 7; + constexpr uint8_t kKBit1 = 1 << 7; + constexpr size_t kExpectedPacketMaskSize = 6; + constexpr size_t kExpectedFecHeaderSize = 24; + // clang-format off + constexpr uint8_t kFlxfecPktMsk[] = {kKBit0 | 0x48, 0x81, + kKBit1 | 0x02, 0x11, 0x00, 0x21}; + constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, + 0x08, 0x44, 0x00, 0x84}; + // clang-format on + constexpr uint8_t kPacketData[] = { + kNoRBit | kNoFBit, kPtRecovery, kLengthRecov[0], kLengthRecov[1], + kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3], + kSsrcCount, kReservedBits, kReservedBits, kReservedBits, + kProtSsrc[0], kProtSsrc[1], kProtSsrc[2], kProtSsrc[3], + kSnBase[0], kSnBase[1], kFlxfecPktMsk[0], kFlxfecPktMsk[1], + kFlxfecPktMsk[2], kFlxfecPktMsk[3], kFlxfecPktMsk[4], kFlxfecPktMsk[5], + kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits}; + const size_t packet_length = sizeof(kPacketData); + ReceivedFecPacket read_packet; + read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(read_packet.pkt->data, kPacketData, packet_length); + read_packet.pkt->length = packet_length; + + FlexfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask, + kExpectedPacketMaskSize, read_packet); +} + +TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit2Set) { + constexpr uint8_t kKBit0 = 0 << 7; + constexpr uint8_t kKBit1 = 0 << 7; + constexpr uint8_t kKBit2 = 1 << 7; + constexpr size_t kExpectedPacketMaskSize = 14; + constexpr size_t kExpectedFecHeaderSize = 32; + // clang-format off + constexpr uint8_t kFlxfcPktMsk[] = {kKBit0 | 0x48, 0x81, + kKBit1 | 0x02, 0x11, 0x00, 0x21, + kKBit2 | 0x01, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11}; + constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, + 0x08, 0x44, 0x00, 0x84, + 0x08, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88}; + // clang-format on + constexpr uint8_t kPacketData[] = { + kNoRBit | kNoFBit, kPtRecovery, kLengthRecov[0], kLengthRecov[1], + kTsRecovery[0], kTsRecovery[1], kTsRecovery[2], kTsRecovery[3], + kSsrcCount, kReservedBits, kReservedBits, kReservedBits, + kProtSsrc[0], kProtSsrc[1], kProtSsrc[2], kProtSsrc[3], + kSnBase[0], kSnBase[1], kFlxfcPktMsk[0], kFlxfcPktMsk[1], + kFlxfcPktMsk[2], kFlxfcPktMsk[3], kFlxfcPktMsk[4], kFlxfcPktMsk[5], + kFlxfcPktMsk[6], kFlxfcPktMsk[7], kFlxfcPktMsk[8], kFlxfcPktMsk[9], + kFlxfcPktMsk[10], kFlxfcPktMsk[11], kFlxfcPktMsk[12], kFlxfcPktMsk[13], + kPayloadBits, kPayloadBits, kPayloadBits, kPayloadBits}; + const size_t packet_length = sizeof(kPacketData); + ReceivedFecPacket read_packet; + read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(read_packet.pkt->data, kPacketData, packet_length); + read_packet.pkt->length = packet_length; + + FlexfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask, + kExpectedPacketMaskSize, read_packet); +} + +TEST(FlexfecHeaderReaderTest, ReadPacketWithoutStreamSpecificHeaderShouldFail) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + + // Simulate short received packet. + ReceivedFecPacket read_packet; + read_packet.ssrc = kFlexfecSsrc; + read_packet.pkt = std::move(written_packet); + read_packet.pkt->length = 12; + + FlexfecHeaderReader reader; + EXPECT_FALSE(reader.ReadFecHeader(&read_packet)); +} + +TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit0SetShouldFail) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + + // Simulate short received packet. + ReceivedFecPacket read_packet; + read_packet.ssrc = kFlexfecSsrc; + read_packet.pkt = std::move(written_packet); + read_packet.pkt->length = 18; + + FlexfecHeaderReader reader; + EXPECT_FALSE(reader.ReadFecHeader(&read_packet)); +} + +TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit1SetShouldFail) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(15, packet_mask.get()); // This expands the packet mask "once". + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + + // Simulate short received packet. + ReceivedFecPacket read_packet; + read_packet.ssrc = kFlexfecSsrc; + read_packet.pkt = std::move(written_packet); + read_packet.pkt->length = 20; + + FlexfecHeaderReader reader; + EXPECT_FALSE(reader.ReadFecHeader(&read_packet)); +} + +TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit2SetShouldFail) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(47, packet_mask.get()); // This expands the packet mask "twice". + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + + // Simulate short received packet. + ReceivedFecPacket read_packet; + read_packet.ssrc = kFlexfecSsrc; + read_packet.pkt = std::move(written_packet); + read_packet.pkt->length = 24; + + FlexfecHeaderReader reader; + EXPECT_FALSE(reader.ReadFecHeader(&read_packet)); +} + +TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0Set) { + constexpr size_t kExpectedPacketMaskSize = 2; + constexpr uint8_t kFlexfecPacketMask[] = {0x88, 0x81}; + constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02}; + Packet written_packet; + written_packet.length = kMediaPacketLength; + for (size_t i = 0; i < written_packet.length; ++i) { + written_packet.data[i] = i; + } + + FlexfecHeaderWriter writer; + writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask, + sizeof(kUlpfecPacketMask), &written_packet); + + VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize, + written_packet); +} + +TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1Set) { + constexpr size_t kExpectedPacketMaskSize = 6; + constexpr uint8_t kFlexfecPacketMask[] = {0x48, 0x81, 0x82, 0x11, 0x00, 0x21}; + constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84}; + Packet written_packet; + written_packet.length = kMediaPacketLength; + for (size_t i = 0; i < written_packet.length; ++i) { + written_packet.data[i] = i; + } + + FlexfecHeaderWriter writer; + writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask, + sizeof(kUlpfecPacketMask), &written_packet); + + VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize, + written_packet); +} + +TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit2Set) { + constexpr size_t kExpectedPacketMaskSize = 14; + constexpr uint8_t kFlexfecPacketMask[] = { + 0x11, 0x11, // K-bit 0 clear. + 0x11, 0x11, 0x11, 0x10, // K-bit 1 clear. + 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // K-bit 2 set. + }; + constexpr uint8_t kUlpfecPacketMask[] = {0x22, 0x22, 0x44, 0x44, 0x44, 0x41}; + Packet written_packet; + written_packet.length = kMediaPacketLength; + for (size_t i = 0; i < written_packet.length; ++i) { + written_packet.data[i] = i; + } + + FlexfecHeaderWriter writer; + writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask, + sizeof(kUlpfecPacketMask), &written_packet); + + VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize, + written_packet); +} + +TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + ClearBit(15, packet_mask.get()); + + FlexfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kFlexfecPacketMaskSizes[0], min_packet_mask_size); + EXPECT_EQ(kFlexfecHeaderSizes[0], writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(FlexfecHeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(15, packet_mask.get()); + + FlexfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size); + EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(FlexfecHeaderWriterTest, + ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + ClearBit(46, packet_mask.get()); + ClearBit(47, packet_mask.get()); + + FlexfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size); + EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(FlexfecHeaderWriterTest, + ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(46, packet_mask.get()); + ClearBit(47, packet_mask.get()); + + FlexfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size); + EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(FlexfecHeaderWriterTest, + ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + ClearBit(46, packet_mask.get()); + SetBit(47, packet_mask.get()); + + FlexfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size); + EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(FlexfecHeaderWriterTest, ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(46, packet_mask.get()); + SetBit(47, packet_mask.get()); + + FlexfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size); + EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(FlexfecHeaderReaderWriterTest, + WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + ClearBit(15, packet_mask.get()); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[0], packet_mask.get(), + kFlexfecPacketMaskSizes[0], *written_packet, + *read_packet); +} + +TEST(FlexfecHeaderReaderWriterTest, + WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(15, packet_mask.get()); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(), + kFlexfecPacketMaskSizes[1], *written_packet, + *read_packet); +} + +TEST(FlexfecHeaderReaderWriterTest, + WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + ClearBit(46, packet_mask.get()); + ClearBit(47, packet_mask.get()); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(), + kFlexfecPacketMaskSizes[1], *written_packet, + *read_packet); +} + +TEST(FlexfecHeaderReaderWriterTest, + WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(46, packet_mask.get()); + ClearBit(47, packet_mask.get()); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(), + kFlexfecPacketMaskSizes[2], *written_packet, + *read_packet); +} + +TEST(FlexfecHeaderReaderWriterTest, + WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + ClearBit(46, packet_mask.get()); + SetBit(47, packet_mask.get()); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(), + kFlexfecPacketMaskSizes[2], *written_packet, + *read_packet); +} + +TEST(FlexfecHeaderReaderWriterTest, + WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + SetBit(46, packet_mask.get()); + SetBit(47, packet_mask.get()); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(), + kFlexfecPacketMaskSizes[2], *written_packet, + *read_packet); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver.cc new file mode 100644 index 0000000000..e26a51b39c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/include/flexfec_receiver.h" + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/scoped_ref_ptr.h" + +namespace webrtc { + +namespace { + +using Packet = ForwardErrorCorrection::Packet; +using ReceivedPacket = ForwardErrorCorrection::ReceivedPacket; + +// Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet. +constexpr size_t kMinFlexfecHeaderSize = 20; + +// How often to log the recovered packets to the text log. +constexpr int kPacketLogIntervalMs = 10000; + +} // namespace + +FlexfecReceiver::FlexfecReceiver( + uint32_t ssrc, + uint32_t protected_media_ssrc, + RecoveredPacketReceiver* recovered_packet_receiver) + : ssrc_(ssrc), + protected_media_ssrc_(protected_media_ssrc), + erasure_code_( + ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)), + recovered_packet_receiver_(recovered_packet_receiver), + clock_(Clock::GetRealTimeClock()), + last_recovered_packet_ms_(-1) { + // It's OK to create this object on a different thread/task queue than + // the one used during main operation. + sequence_checker_.Detach(); +} + +FlexfecReceiver::~FlexfecReceiver() = default; + +void FlexfecReceiver::OnRtpPacket(const RtpPacketReceived& packet) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + std::unique_ptr<ReceivedPacket> received_packet = AddReceivedPacket(packet); + if (!received_packet) + return; + + ProcessReceivedPacket(*received_packet); +} + +FecPacketCounter FlexfecReceiver::GetPacketCounter() const { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + return packet_counter_; +} + +// TODO(eladalon): Consider using packet.recovered() to avoid processing +// recovered packets here. +std::unique_ptr<ReceivedPacket> FlexfecReceiver::AddReceivedPacket( + const RtpPacketReceived& packet) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + // RTP packets with a full base header (12 bytes), but without payload, + // could conceivably be useful in the decoding. Therefore we check + // with a non-strict inequality here. + RTC_DCHECK_GE(packet.size(), kRtpHeaderSize); + + // Demultiplex based on SSRC, and insert into erasure code decoder. + std::unique_ptr<ReceivedPacket> received_packet(new ReceivedPacket()); + received_packet->seq_num = packet.SequenceNumber(); + received_packet->ssrc = packet.Ssrc(); + if (received_packet->ssrc == ssrc_) { + // This is a FlexFEC packet. + if (packet.payload_size() < kMinFlexfecHeaderSize) { + RTC_LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding."; + return nullptr; + } + received_packet->is_fec = true; + ++packet_counter_.num_fec_packets; + + // Insert packet payload into erasure code. + // TODO(brandtr): Remove this memcpy when the FEC packet classes + // are using COW buffers internally. + received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet()); + auto payload = packet.payload(); + memcpy(received_packet->pkt->data, payload.data(), payload.size()); + received_packet->pkt->length = payload.size(); + } else { + // This is a media packet, or a FlexFEC packet belonging to some + // other FlexFEC stream. + if (received_packet->ssrc != protected_media_ssrc_) { + return nullptr; + } + received_packet->is_fec = false; + + // Insert entire packet into erasure code. + // TODO(brandtr): Remove this memcpy too. + received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(received_packet->pkt->data, packet.data(), packet.size()); + received_packet->pkt->length = packet.size(); + } + + ++packet_counter_.num_packets; + + return received_packet; +} + +// Note that the implementation of this member function and the implementation +// in UlpfecReceiver::ProcessReceivedFec() are slightly different. +// This implementation only returns _recovered_ media packets through the +// callback, whereas the implementation in UlpfecReceiver returns _all inserted_ +// media packets through the callback. The latter behaviour makes sense +// for ULPFEC, since the ULPFEC receiver is owned by the RtpVideoStreamReceiver. +// Here, however, the received media pipeline is more decoupled from the +// FlexFEC decoder, and we therefore do not interfere with the reception +// of non-recovered media packets. +void FlexfecReceiver::ProcessReceivedPacket( + const ReceivedPacket& received_packet) { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + // Decode. + erasure_code_->DecodeFec(received_packet, &recovered_packets_); + + // Return recovered packets through callback. + for (const auto& recovered_packet : recovered_packets_) { + RTC_CHECK(recovered_packet); + if (recovered_packet->returned) { + continue; + } + ++packet_counter_.num_recovered_packets; + // Set this flag first, since OnRecoveredPacket may end up here + // again, with the same packet. + recovered_packet->returned = true; + RTC_CHECK(recovered_packet->pkt); + recovered_packet_receiver_->OnRecoveredPacket( + recovered_packet->pkt->data, recovered_packet->pkt->length); + // Periodically log the incoming packets. + int64_t now_ms = clock_->TimeInMilliseconds(); + if (now_ms - last_recovered_packet_ms_ > kPacketLogIntervalMs) { + uint32_t media_ssrc = + ForwardErrorCorrection::ParseSsrc(recovered_packet->pkt->data); + RTC_LOG(LS_VERBOSE) << "Recovered media packet with SSRC: " << media_ssrc + << " from FlexFEC stream with SSRC: " << ssrc_ << "."; + last_recovered_packet_ms_ = now_ms; + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc new file mode 100644 index 0000000000..3e2e4f0ae7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2016 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 <algorithm> +#include <memory> + +#include "modules/rtp_rtcp/include/flexfec_receiver.h" +#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h" +#include "modules/rtp_rtcp/source/fec_test_helper.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "rtc_base/basictypes.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +using ::testing::_; +using ::testing::Args; +using ::testing::ElementsAreArray; +using ::testing::Return; + +using test::fec::FlexfecPacketGenerator; +using Packet = ForwardErrorCorrection::Packet; +using PacketList = ForwardErrorCorrection::PacketList; + +constexpr size_t kPayloadLength = 500; +constexpr uint32_t kFlexfecSsrc = 42984; +constexpr uint32_t kMediaSsrc = 8353; + +RtpPacketReceived ParsePacket(const Packet& packet) { + RtpPacketReceived parsed_packet; + EXPECT_TRUE(parsed_packet.Parse(packet.data, packet.length)); + return parsed_packet; +} + +} // namespace + +class FlexfecReceiverForTest : public FlexfecReceiver { + public: + FlexfecReceiverForTest(uint32_t ssrc, + uint32_t protected_media_ssrc, + RecoveredPacketReceiver* recovered_packet_receiver) + : FlexfecReceiver(ssrc, protected_media_ssrc, recovered_packet_receiver) { + } + // Expose methods for tests. + using FlexfecReceiver::AddReceivedPacket; + using FlexfecReceiver::ProcessReceivedPacket; +}; + +class FlexfecReceiverTest : public ::testing::Test { + protected: + FlexfecReceiverTest() + : receiver_(kFlexfecSsrc, kMediaSsrc, &recovered_packet_receiver_), + erasure_code_( + ForwardErrorCorrection::CreateFlexfec(kFlexfecSsrc, kMediaSsrc)), + packet_generator_(kMediaSsrc, kFlexfecSsrc) {} + + // Generates |num_media_packets| corresponding to a single frame. + void PacketizeFrame(size_t num_media_packets, + size_t frame_offset, + PacketList* media_packets); + + // Generates |num_fec_packets| FEC packets, given |media_packets|. + std::list<Packet*> EncodeFec(const PacketList& media_packets, + size_t num_fec_packets); + + FlexfecReceiverForTest receiver_; + std::unique_ptr<ForwardErrorCorrection> erasure_code_; + + FlexfecPacketGenerator packet_generator_; + ::testing::StrictMock<MockRecoveredPacketReceiver> recovered_packet_receiver_; +}; + +void FlexfecReceiverTest::PacketizeFrame(size_t num_media_packets, + size_t frame_offset, + PacketList* media_packets) { + packet_generator_.NewFrame(num_media_packets); + for (size_t i = 0; i < num_media_packets; ++i) { + std::unique_ptr<Packet> next_packet( + packet_generator_.NextPacket(frame_offset + i, kPayloadLength)); + media_packets->push_back(std::move(next_packet)); + } +} + +std::list<Packet*> FlexfecReceiverTest::EncodeFec( + const PacketList& media_packets, + size_t num_fec_packets) { + const uint8_t protection_factor = + num_fec_packets * 255 / media_packets.size(); + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr FecMaskType kFecMaskType = kFecMaskRandom; + std::list<Packet*> fec_packets; + EXPECT_EQ(0, erasure_code_->EncodeFec( + media_packets, protection_factor, kNumImportantPackets, + kUseUnequalProtection, kFecMaskType, &fec_packets)); + EXPECT_EQ(num_fec_packets, fec_packets.size()); + return fec_packets; +} + +TEST_F(FlexfecReceiverTest, ReceivesMediaPacket) { + packet_generator_.NewFrame(1); + std::unique_ptr<Packet> media_packet( + packet_generator_.NextPacket(0, kPayloadLength)); + + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet = + receiver_.AddReceivedPacket(ParsePacket(*media_packet)); + ASSERT_TRUE(received_packet); + receiver_.ProcessReceivedPacket(*received_packet); +} + +TEST_F(FlexfecReceiverTest, ReceivesMediaAndFecPackets) { + const size_t kNumMediaPackets = 1; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + const auto& media_packet = media_packets.front(); + auto fec_packet = packet_generator_.BuildFlexfecPacket(*fec_packets.front()); + + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet = + receiver_.AddReceivedPacket(ParsePacket(*media_packet)); + ASSERT_TRUE(received_packet); + receiver_.ProcessReceivedPacket(*received_packet); + received_packet = receiver_.AddReceivedPacket(ParsePacket(*fec_packet)); + ASSERT_TRUE(received_packet); + receiver_.ProcessReceivedPacket(*received_packet); +} + +TEST_F(FlexfecReceiverTest, FailsOnTruncatedFecPacket) { + const size_t kNumMediaPackets = 1; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + const auto& media_packet = media_packets.front(); + // Simulate truncated FlexFEC payload. + fec_packets.front()->length = 1; + auto fec_packet = packet_generator_.BuildFlexfecPacket(*fec_packets.front()); + + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet = + receiver_.AddReceivedPacket(ParsePacket(*media_packet)); + ASSERT_TRUE(received_packet); + receiver_.ProcessReceivedPacket(*received_packet); + EXPECT_FALSE(receiver_.AddReceivedPacket(ParsePacket(*fec_packet))); +} + +TEST_F(FlexfecReceiverTest, FailsOnUnknownMediaSsrc) { + const size_t kNumMediaPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + auto& media_packet = media_packets.front(); + // Corrupt the SSRC. + media_packet->data[8] = 0; + media_packet->data[9] = 1; + media_packet->data[10] = 2; + media_packet->data[11] = 3; + + EXPECT_FALSE(receiver_.AddReceivedPacket(ParsePacket(*media_packet))); +} + +TEST_F(FlexfecReceiverTest, FailsOnUnknownFecSsrc) { + const size_t kNumMediaPackets = 1; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + const auto& media_packet = media_packets.front(); + auto fec_packet = packet_generator_.BuildFlexfecPacket(*fec_packets.front()); + // Corrupt the SSRC. + fec_packet->data[8] = 4; + fec_packet->data[9] = 5; + fec_packet->data[10] = 6; + fec_packet->data[11] = 7; + + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet = + receiver_.AddReceivedPacket(ParsePacket(*media_packet)); + ASSERT_TRUE(received_packet); + receiver_.ProcessReceivedPacket(*received_packet); + EXPECT_FALSE(receiver_.AddReceivedPacket(ParsePacket(*fec_packet))); +} + +TEST_F(FlexfecReceiverTest, ReceivesMultiplePackets) { + const size_t kNumMediaPackets = 2; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Receive all media packets. + for (const auto& media_packet : media_packets) { + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet = + receiver_.AddReceivedPacket(ParsePacket(*media_packet)); + ASSERT_TRUE(received_packet); + receiver_.ProcessReceivedPacket(*received_packet); + } + + // Receive FEC packet. + auto fec_packet = fec_packets.front(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(*fec_packet); + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet = + receiver_.AddReceivedPacket(ParsePacket(*packet_with_rtp_header)); + ASSERT_TRUE(received_packet); + receiver_.ProcessReceivedPacket(*received_packet); +} + +TEST_F(FlexfecReceiverTest, RecoversFromSingleMediaLoss) { + const size_t kNumMediaPackets = 2; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Receive first media packet but drop second. + auto media_it = media_packets.begin(); + receiver_.OnRtpPacket(ParsePacket(**media_it)); + + // Receive FEC packet and ensure recovery of lost media packet. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(**fec_it); + media_it++; + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_it)->length)) + .With( + Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length))); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); +} + +TEST_F(FlexfecReceiverTest, RecoversFromDoubleMediaLoss) { + const size_t kNumMediaPackets = 2; + const size_t kNumFecPackets = 2; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Drop both media packets. + + // Receive first FEC packet and recover first lost media packet. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(**fec_it); + auto media_it = media_packets.begin(); + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_it)->length)) + .With( + Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length))); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); + + // Receive second FEC packet and recover second lost media packet. + fec_it++; + packet_with_rtp_header = packet_generator_.BuildFlexfecPacket(**fec_it); + media_it++; + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_it)->length)) + .With( + Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length))); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); +} + +TEST_F(FlexfecReceiverTest, DoesNotRecoverFromMediaAndFecLoss) { + const size_t kNumMediaPackets = 2; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Receive first media packet. + auto media_it = media_packets.begin(); + receiver_.OnRtpPacket(ParsePacket(**media_it)); + + // Drop second media packet and FEC packet. Do not expect call back. +} + +TEST_F(FlexfecReceiverTest, DoesNotCallbackTwice) { + const size_t kNumMediaPackets = 2; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Receive first media packet but drop second. + auto media_it = media_packets.begin(); + receiver_.OnRtpPacket(ParsePacket(**media_it)); + + // Receive FEC packet and ensure recovery of lost media packet. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(**fec_it); + media_it++; + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_it)->length)) + .With( + Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length))); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); + + // Receive the FEC packet again, but do not call back. + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); + + // Receive the first media packet again, but do not call back. + media_it = media_packets.begin(); + receiver_.OnRtpPacket(ParsePacket(**media_it)); + + // Receive the second media packet again (the one recovered above), + // but do not call back again. + media_it++; + receiver_.OnRtpPacket(ParsePacket(**media_it)); +} + +// Here we are implicitly assuming packet masks that are suitable for +// this type of 50% correlated loss. If we are changing our precomputed +// packet masks, this test might need to be updated. +TEST_F(FlexfecReceiverTest, RecoversFrom50PercentLoss) { + const size_t kNumFecPackets = 5; + const size_t kNumFrames = 2 * kNumFecPackets; + const size_t kNumMediaPacketsPerFrame = 1; + + PacketList media_packets; + for (size_t i = 0; i < kNumFrames; ++i) { + PacketizeFrame(kNumMediaPacketsPerFrame, i, &media_packets); + } + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Drop every second media packet. + auto media_it = media_packets.begin(); + while (media_it != media_packets.end()) { + receiver_.OnRtpPacket(ParsePacket(**media_it)); + ++media_it; + if (media_it == media_packets.end()) { + break; + } + ++media_it; + } + + // Receive all FEC packets. + media_it = media_packets.begin(); + for (const auto& fec_packet : fec_packets) { + std::unique_ptr<Packet> fec_packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(*fec_packet); + ++media_it; + if (media_it == media_packets.end()) { + break; + } + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_it)->length)) + .With(Args<0, 1>( + ElementsAreArray((*media_it)->data, (*media_it)->length))); + receiver_.OnRtpPacket(ParsePacket(*fec_packet_with_rtp_header)); + ++media_it; + } +} + +TEST_F(FlexfecReceiverTest, DelayedFecPacketDoesHelp) { + // These values need to be updated if the underlying erasure code + // implementation changes. + const size_t kNumFrames = 48; + const size_t kNumMediaPacketsPerFrame = 1; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPacketsPerFrame, 0, &media_packets); + PacketizeFrame(kNumMediaPacketsPerFrame, 1, &media_packets); + // Protect two first frames. + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + for (size_t i = 2; i < kNumFrames; ++i) { + PacketizeFrame(kNumMediaPacketsPerFrame, i, &media_packets); + } + + // Drop first media packet and delay FEC packet. + auto media_it = media_packets.begin(); + ++media_it; + + // Receive all other media packets. + while (media_it != media_packets.end()) { + receiver_.OnRtpPacket(ParsePacket(**media_it)); + ++media_it; + } + + // Receive FEC packet and recover first media packet. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(**fec_it); + media_it = media_packets.begin(); + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_it)->length)) + .With( + Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length))); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); +} + +TEST_F(FlexfecReceiverTest, TooDelayedFecPacketDoesNotHelp) { + // These values need to be updated if the underlying erasure code + // implementation changes. + const size_t kNumFrames = 49; + const size_t kNumMediaPacketsPerFrame = 1; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPacketsPerFrame, 0, &media_packets); + PacketizeFrame(kNumMediaPacketsPerFrame, 1, &media_packets); + // Protect two first frames. + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + for (size_t i = 2; i < kNumFrames; ++i) { + PacketizeFrame(kNumMediaPacketsPerFrame, i, &media_packets); + } + + // Drop first media packet and delay FEC packet. + auto media_it = media_packets.begin(); + ++media_it; + + // Receive all other media packets. + while (media_it != media_packets.end()) { + receiver_.OnRtpPacket(ParsePacket(**media_it)); + ++media_it; + } + + // Receive FEC packet. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(**fec_it); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); + + // Do not expect a call back. +} + +TEST_F(FlexfecReceiverTest, RecoversWithMediaPacketsOutOfOrder) { + const size_t kNumMediaPackets = 6; + const size_t kNumFecPackets = 2; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Lose two media packets, and receive the others out of order. + auto media_it = media_packets.begin(); + auto media_packet0 = media_it++; + auto media_packet1 = media_it++; + auto media_packet2 = media_it++; + auto media_packet3 = media_it++; + auto media_packet4 = media_it++; + auto media_packet5 = media_it++; + receiver_.OnRtpPacket(ParsePacket(**media_packet5)); + receiver_.OnRtpPacket(ParsePacket(**media_packet2)); + receiver_.OnRtpPacket(ParsePacket(**media_packet3)); + receiver_.OnRtpPacket(ParsePacket(**media_packet0)); + + // Expect to recover lost media packets. + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_packet1)->length)) + .With(Args<0, 1>( + ElementsAreArray((*media_packet1)->data, (*media_packet1)->length))); + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_packet4)->length)) + .With(Args<0, 1>( + ElementsAreArray((*media_packet4)->data, (*media_packet4)->length))); + + // Add FEC packets. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header; + while (fec_it != fec_packets.end()) { + packet_with_rtp_header = packet_generator_.BuildFlexfecPacket(**fec_it); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); + ++fec_it; + } +} + +// Recovered media packets may be fed back into the FlexfecReceiver by the +// callback. This test ensures the idempotency of such a situation. +TEST_F(FlexfecReceiverTest, RecoveryCallbackDoesNotLoopInfinitely) { + class LoopbackRecoveredPacketReceiver : public RecoveredPacketReceiver { + public: + const int kMaxRecursionDepth = 10; + + LoopbackRecoveredPacketReceiver() + : receiver_(nullptr), + did_receive_call_back_(false), + recursion_depth_(0), + deep_recursion_(false) {} + + void SetReceiver(FlexfecReceiver* receiver) { receiver_ = receiver; } + bool DidReceiveCallback() const { return did_receive_call_back_; } + bool DeepRecursion() const { return deep_recursion_; } + + // Implements RecoveredPacketReceiver. + void OnRecoveredPacket(const uint8_t* packet, size_t length) { + RtpPacketReceived parsed_packet; + EXPECT_TRUE(parsed_packet.Parse(packet, length)); + + did_receive_call_back_ = true; + + if (recursion_depth_ > kMaxRecursionDepth) { + deep_recursion_ = true; + return; + } + ++recursion_depth_; + RTC_DCHECK(receiver_); + receiver_->OnRtpPacket(parsed_packet); + --recursion_depth_; + } + + private: + FlexfecReceiver* receiver_; + bool did_receive_call_back_; + int recursion_depth_; + bool deep_recursion_; + } loopback_recovered_packet_receiver; + + // Feed recovered packets back into |receiver|. + FlexfecReceiver receiver(kFlexfecSsrc, kMediaSsrc, + &loopback_recovered_packet_receiver); + loopback_recovered_packet_receiver.SetReceiver(&receiver); + + const size_t kNumMediaPackets = 2; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Receive first media packet but drop second. + auto media_it = media_packets.begin(); + receiver.OnRtpPacket(ParsePacket(**media_it)); + + // Receive FEC packet and verify that a packet was recovered. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(**fec_it); + receiver.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); + EXPECT_TRUE(loopback_recovered_packet_receiver.DidReceiveCallback()); + EXPECT_FALSE(loopback_recovered_packet_receiver.DeepRecursion()); +} + +TEST_F(FlexfecReceiverTest, CalculatesNumberOfPackets) { + const size_t kNumMediaPackets = 2; + const size_t kNumFecPackets = 1; + + PacketList media_packets; + PacketizeFrame(kNumMediaPackets, 0, &media_packets); + std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets); + + // Receive first media packet but drop second. + auto media_it = media_packets.begin(); + receiver_.OnRtpPacket(ParsePacket(**media_it)); + + // Receive FEC packet and ensure recovery of lost media packet. + auto fec_it = fec_packets.begin(); + std::unique_ptr<Packet> packet_with_rtp_header = + packet_generator_.BuildFlexfecPacket(**fec_it); + media_it++; + EXPECT_CALL(recovered_packet_receiver_, + OnRecoveredPacket(_, (*media_it)->length)) + .With( + Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length))); + receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header)); + + // Check stats calculations. + FecPacketCounter packet_counter = receiver_.GetPacketCounter(); + EXPECT_EQ(2U, packet_counter.num_packets); + EXPECT_EQ(1U, packet_counter.num_fec_packets); + EXPECT_EQ(1U, packet_counter.num_recovered_packets); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc new file mode 100644 index 0000000000..f046a349ee --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/include/flexfec_sender.h" + +#include <utility> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +namespace { + +// Let first sequence number be in the first half of the interval. +constexpr uint16_t kMaxInitRtpSeqNumber = 0x7fff; + +// See breakdown in flexfec_header_reader_writer.cc. +constexpr size_t kFlexfecMaxHeaderSize = 32; + +// Since we will mainly use FlexFEC to protect video streams, we use a 90 kHz +// clock for the RTP timestamps. (This is according to the RFC, which states +// that it is RECOMMENDED to use the same clock frequency for FlexFEC as for +// the protected media stream.) +// The constant converts from clock millisecond timestamps to the 90 kHz +// RTP timestamp. +const int kMsToRtpTimestamp = kVideoPayloadTypeFrequency / 1000; + +// How often to log the generated FEC packets to the text log. +constexpr int64_t kPacketLogIntervalMs = 10000; + +RtpHeaderExtensionMap RegisterBweExtensions( + const std::vector<RtpExtension>& rtp_header_extensions) { + RtpHeaderExtensionMap map; + for (const auto& extension : rtp_header_extensions) { + if (extension.uri == TransportSequenceNumber::kUri) { + map.Register<TransportSequenceNumber>(extension.id); + } else if (extension.uri == AbsoluteSendTime::kUri) { + map.Register<AbsoluteSendTime>(extension.id); + } else if (extension.uri == TransmissionOffset::kUri) { + map.Register<TransmissionOffset>(extension.id); + } else { + RTC_LOG(LS_INFO) + << "FlexfecSender only supports RTP header extensions for " + << "BWE, so the extension " << extension.ToString() + << " will not be used."; + } + } + return map; +} + +} // namespace + +FlexfecSender::FlexfecSender( + int payload_type, + uint32_t ssrc, + uint32_t protected_media_ssrc, + const std::vector<RtpExtension>& rtp_header_extensions, + rtc::ArrayView<const RtpExtensionSize> extension_sizes, + const RtpState* rtp_state, + Clock* clock) + : clock_(clock), + random_(clock_->TimeInMicroseconds()), + last_generated_packet_ms_(-1), + payload_type_(payload_type), + // Reset RTP state if this is not the first time we are operating. + // Otherwise, randomize the initial timestamp offset and RTP sequence + // numbers. (This is not intended to be cryptographically strong.) + timestamp_offset_(rtp_state ? rtp_state->start_timestamp + : random_.Rand<uint32_t>()), + ssrc_(ssrc), + protected_media_ssrc_(protected_media_ssrc), + seq_num_(rtp_state ? rtp_state->sequence_number + : random_.Rand(1, kMaxInitRtpSeqNumber)), + ulpfec_generator_( + ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)), + rtp_header_extension_map_(RegisterBweExtensions(rtp_header_extensions)), + header_extensions_size_( + rtp_header_extension_map_.GetTotalLengthInBytes(extension_sizes)) { + // This object should not have been instantiated if FlexFEC is disabled. + RTC_DCHECK_GE(payload_type, 0); + RTC_DCHECK_LE(payload_type, 127); +} + +FlexfecSender::~FlexfecSender() = default; + +// We are reusing the implementation from UlpfecGenerator for SetFecParameters, +// AddRtpPacketAndGenerateFec, and FecAvailable. +void FlexfecSender::SetFecParameters(const FecProtectionParams& params) { + ulpfec_generator_.SetFecParameters(params); +} + +bool FlexfecSender::AddRtpPacketAndGenerateFec(const RtpPacketToSend& packet) { + // TODO(brandtr): Generalize this SSRC check when we support multistream + // protection. + RTC_DCHECK_EQ(packet.Ssrc(), protected_media_ssrc_); + return ulpfec_generator_.AddRtpPacketAndGenerateFec( + packet.data(), packet.payload_size(), packet.headers_size()) == 0; +} + +bool FlexfecSender::FecAvailable() const { + return ulpfec_generator_.FecAvailable(); +} + +std::vector<std::unique_ptr<RtpPacketToSend>> FlexfecSender::GetFecPackets() { + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets_to_send; + fec_packets_to_send.reserve(ulpfec_generator_.generated_fec_packets_.size()); + for (const auto& fec_packet : ulpfec_generator_.generated_fec_packets_) { + std::unique_ptr<RtpPacketToSend> fec_packet_to_send( + new RtpPacketToSend(&rtp_header_extension_map_)); + + // RTP header. + fec_packet_to_send->SetMarker(false); + fec_packet_to_send->SetPayloadType(payload_type_); + fec_packet_to_send->SetSequenceNumber(seq_num_++); + fec_packet_to_send->SetTimestamp( + timestamp_offset_ + + static_cast<uint32_t>(kMsToRtpTimestamp * + clock_->TimeInMilliseconds())); + // Set "capture time" so that the TransmissionOffset header extension + // can be set by the RTPSender. + fec_packet_to_send->set_capture_time_ms(clock_->TimeInMilliseconds()); + fec_packet_to_send->SetSsrc(ssrc_); + // Reserve extensions, if registered. These will be set by the RTPSender. + fec_packet_to_send->ReserveExtension<AbsoluteSendTime>(); + fec_packet_to_send->ReserveExtension<TransmissionOffset>(); + fec_packet_to_send->ReserveExtension<TransportSequenceNumber>(); + + // RTP payload. + uint8_t* payload = fec_packet_to_send->AllocatePayload(fec_packet->length); + memcpy(payload, fec_packet->data, fec_packet->length); + + fec_packets_to_send.push_back(std::move(fec_packet_to_send)); + } + ulpfec_generator_.ResetState(); + + int64_t now_ms = clock_->TimeInMilliseconds(); + if (!fec_packets_to_send.empty() && + now_ms - last_generated_packet_ms_ > kPacketLogIntervalMs) { + RTC_LOG(LS_VERBOSE) << "Generated " << fec_packets_to_send.size() + << " FlexFEC packets with payload type: " + << payload_type_ << " and SSRC: " << ssrc_ << "."; + last_generated_packet_ms_ = now_ms; + } + + return fec_packets_to_send; +} + +// The overhead is BWE RTP header extensions and FlexFEC header. +size_t FlexfecSender::MaxPacketOverhead() const { + return header_extensions_size_ + kFlexfecMaxHeaderSize; +} + +RtpState FlexfecSender::GetRtpState() { + RtpState rtp_state; + rtp_state.sequence_number = seq_num_; + rtp_state.start_timestamp = timestamp_offset_; + return rtp_state; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc new file mode 100644 index 0000000000..aa729ed0b8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2016 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 <vector> + +#include "api/rtpparameters.h" +#include "modules/rtp_rtcp/include/flexfec_sender.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/fec_test_helper.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "modules/rtp_rtcp/source/rtp_sender.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "system_wrappers/include/clock.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +using RtpUtility::Word32Align; +using test::fec::AugmentedPacket; +using test::fec::AugmentedPacketGenerator; + +constexpr int kFlexfecPayloadType = 123; +constexpr uint32_t kMediaSsrc = 1234; +constexpr uint32_t kFlexfecSsrc = 5678; +const std::vector<RtpExtension> kNoRtpHeaderExtensions; +const std::vector<RtpExtensionSize> kNoRtpHeaderExtensionSizes; +// Assume a single protected media SSRC. +constexpr size_t kFlexfecMaxHeaderSize = 32; +constexpr size_t kPayloadLength = 50; + +constexpr int64_t kInitialSimulatedClockTime = 1; +// These values are deterministically given by the PRNG, due to our fixed seed. +// They should be updated if the PRNG implementation changes. +constexpr uint16_t kDeterministicSequenceNumber = 28732; +constexpr uint32_t kDeterministicTimestamp = 2305613085; + +std::unique_ptr<RtpPacketToSend> GenerateSingleFlexfecPacket( + FlexfecSender* sender) { + // Parameters selected to generate a single FEC packet. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + constexpr size_t kNumPackets = 4; + + sender->SetFecParameters(params); + AugmentedPacketGenerator packet_generator(kMediaSsrc); + packet_generator.NewFrame(kNumPackets); + for (size_t i = 0; i < kNumPackets; ++i) { + std::unique_ptr<AugmentedPacket> packet = + packet_generator.NextPacket(i, kPayloadLength); + RtpPacketToSend rtp_packet(nullptr); // No header extensions. + rtp_packet.Parse(packet->data, packet->length); + EXPECT_TRUE(sender->AddRtpPacketAndGenerateFec(rtp_packet)); + } + EXPECT_TRUE(sender->FecAvailable()); + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = + sender->GetFecPackets(); + EXPECT_FALSE(sender->FecAvailable()); + EXPECT_EQ(1U, fec_packets.size()); + + return std::move(fec_packets.front()); +} + +} // namespace + +TEST(FlexfecSenderTest, Ssrc) { + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + + EXPECT_EQ(kFlexfecSsrc, sender.ssrc()); +} + +TEST(FlexfecSenderTest, NoFecAvailableBeforeMediaAdded) { + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + + EXPECT_FALSE(sender.FecAvailable()); + auto fec_packets = sender.GetFecPackets(); + EXPECT_EQ(0U, fec_packets.size()); +} + +TEST(FlexfecSenderTest, ProtectOneFrameWithOneFecPacket) { + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size()); + EXPECT_FALSE(fec_packet->Marker()); + EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType()); + EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber()); + EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp()); + EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc()); + EXPECT_LE(kPayloadLength, fec_packet->payload_size()); +} + +TEST(FlexfecSenderTest, ProtectTwoFramesWithOneFecPacket) { + // FEC parameters selected to generate a single FEC packet per frame. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 2; + params.fec_mask_type = kFecMaskRandom; + constexpr size_t kNumFrames = 2; + constexpr size_t kNumPacketsPerFrame = 2; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + sender.SetFecParameters(params); + + AugmentedPacketGenerator packet_generator(kMediaSsrc); + for (size_t i = 0; i < kNumFrames; ++i) { + packet_generator.NewFrame(kNumPacketsPerFrame); + for (size_t j = 0; j < kNumPacketsPerFrame; ++j) { + std::unique_ptr<AugmentedPacket> packet = + packet_generator.NextPacket(i, kPayloadLength); + RtpPacketToSend rtp_packet(nullptr); + rtp_packet.Parse(packet->data, packet->length); + EXPECT_TRUE(sender.AddRtpPacketAndGenerateFec(rtp_packet)); + } + } + EXPECT_TRUE(sender.FecAvailable()); + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = + sender.GetFecPackets(); + EXPECT_FALSE(sender.FecAvailable()); + ASSERT_EQ(1U, fec_packets.size()); + + RtpPacketToSend* fec_packet = fec_packets.front().get(); + EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size()); + EXPECT_FALSE(fec_packet->Marker()); + EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType()); + EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber()); + EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp()); + EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc()); +} + +TEST(FlexfecSenderTest, ProtectTwoFramesWithTwoFecPackets) { + // FEC parameters selected to generate a single FEC packet per frame. + FecProtectionParams params; + params.fec_rate = 30; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + constexpr size_t kNumFrames = 2; + constexpr size_t kNumPacketsPerFrame = 2; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + sender.SetFecParameters(params); + + AugmentedPacketGenerator packet_generator(kMediaSsrc); + for (size_t i = 0; i < kNumFrames; ++i) { + packet_generator.NewFrame(kNumPacketsPerFrame); + for (size_t j = 0; j < kNumPacketsPerFrame; ++j) { + std::unique_ptr<AugmentedPacket> packet = + packet_generator.NextPacket(i, kPayloadLength); + RtpPacketToSend rtp_packet(nullptr); + rtp_packet.Parse(packet->data, packet->length); + EXPECT_TRUE(sender.AddRtpPacketAndGenerateFec(rtp_packet)); + } + EXPECT_TRUE(sender.FecAvailable()); + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = + sender.GetFecPackets(); + EXPECT_FALSE(sender.FecAvailable()); + ASSERT_EQ(1U, fec_packets.size()); + + RtpPacketToSend* fec_packet = fec_packets.front().get(); + EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size()); + EXPECT_FALSE(fec_packet->Marker()); + EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType()); + EXPECT_EQ(static_cast<uint16_t>(kDeterministicSequenceNumber + i), + fec_packet->SequenceNumber()); + EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp()); + EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc()); + } +} + +// In the tests, we only consider RTP header extensions that are useful for BWE. +TEST(FlexfecSenderTest, NoRtpHeaderExtensionsForBweByDefault) { + const std::vector<RtpExtension> kRtpHeaderExtensions{}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>()); + EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>()); + EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>()); +} + +TEST(FlexfecSenderTest, RegisterAbsoluteSendTimeRtpHeaderExtension) { + const std::vector<RtpExtension> kRtpHeaderExtensions{ + {RtpExtension::kAbsSendTimeUri, 1}}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>()); + EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>()); + EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>()); +} + +TEST(FlexfecSenderTest, RegisterTransmissionOffsetRtpHeaderExtension) { + const std::vector<RtpExtension> kRtpHeaderExtensions{ + {RtpExtension::kTimestampOffsetUri, 1}}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>()); + EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>()); + EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>()); +} + +TEST(FlexfecSenderTest, RegisterTransportSequenceNumberRtpHeaderExtension) { + const std::vector<RtpExtension> kRtpHeaderExtensions{ + {RtpExtension::kTransportSequenceNumberUri, 1}}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>()); + EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>()); + EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>()); +} + +TEST(FlexfecSenderTest, RegisterAllRtpHeaderExtensionsForBwe) { + const std::vector<RtpExtension> kRtpHeaderExtensions{ + {RtpExtension::kAbsSendTimeUri, 1}, + {RtpExtension::kTimestampOffsetUri, 2}, + {RtpExtension::kTransportSequenceNumberUri, 3}}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>()); + EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>()); + EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>()); +} + +TEST(FlexfecSenderTest, MaxPacketOverhead) { + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + nullptr /* rtp_state */, &clock); + + EXPECT_EQ(kFlexfecMaxHeaderSize, sender.MaxPacketOverhead()); +} + +TEST(FlexfecSenderTest, MaxPacketOverheadWithExtensions) { + const std::vector<RtpExtension> kRtpHeaderExtensions{ + {RtpExtension::kAbsSendTimeUri, 1}, + {RtpExtension::kTimestampOffsetUri, 2}, + {RtpExtension::kTransportSequenceNumberUri, 3}}; + SimulatedClock clock(kInitialSimulatedClockTime); + const size_t kExtensionHeaderLength = 1; + const size_t kRtpOneByteHeaderLength = 4; + const size_t kExtensionsTotalSize = Word32Align( + kRtpOneByteHeaderLength + + kExtensionHeaderLength + AbsoluteSendTime::kValueSizeBytes + + kExtensionHeaderLength + TransmissionOffset::kValueSizeBytes + + kExtensionHeaderLength + TransportSequenceNumber::kValueSizeBytes); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, RTPSender::FecExtensionSizes(), + nullptr /* rtp_state */, &clock); + + EXPECT_EQ(kExtensionsTotalSize + kFlexfecMaxHeaderSize, + sender.MaxPacketOverhead()); +} + +TEST(FlexfecSenderTest, SetsAndGetsRtpState) { + RtpState initial_rtp_state; + initial_rtp_state.sequence_number = 100; + initial_rtp_state.start_timestamp = 200; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes, + &initial_rtp_state, &clock); + + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + EXPECT_EQ(initial_rtp_state.sequence_number, fec_packet->SequenceNumber()); + EXPECT_EQ(initial_rtp_state.start_timestamp, fec_packet->Timestamp()); + + clock.AdvanceTimeMilliseconds(1000); + fec_packet = GenerateSingleFlexfecPacket(&sender); + EXPECT_EQ(initial_rtp_state.sequence_number + 1, + fec_packet->SequenceNumber()); + EXPECT_EQ(initial_rtp_state.start_timestamp + 1 * kVideoPayloadTypeFrequency, + fec_packet->Timestamp()); + + RtpState updated_rtp_state = sender.GetRtpState(); + EXPECT_EQ(initial_rtp_state.sequence_number + 2, + updated_rtp_state.sequence_number); + EXPECT_EQ(initial_rtp_state.start_timestamp, + updated_rtp_state.start_timestamp); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc new file mode 100644 index 0000000000..23c9fa08cd --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc @@ -0,0 +1,779 @@ +/* + * 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 "modules/rtp_rtcp/source/forward_error_correction.h" + +#include <string.h> + +#include <algorithm> +#include <iterator> +#include <utility> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h" +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/mod_ops.h" + +namespace webrtc { + +namespace { +// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. +constexpr size_t kTransportOverhead = 28; +} // namespace + +ForwardErrorCorrection::Packet::Packet() : length(0), data(), ref_count_(0) {} +ForwardErrorCorrection::Packet::~Packet() = default; + +int32_t ForwardErrorCorrection::Packet::AddRef() { + return ++ref_count_; +} + +int32_t ForwardErrorCorrection::Packet::Release() { + int32_t ref_count; + ref_count = --ref_count_; + if (ref_count == 0) + delete this; + return ref_count; +} + +// This comparator is used to compare std::unique_ptr's pointing to +// subclasses of SortablePackets. It needs to be parametric since +// the std::unique_ptr's are not covariant w.r.t. the types that +// they are pointing to. +template <typename S, typename T> +bool ForwardErrorCorrection::SortablePacket::LessThan::operator() ( + const S& first, + const T& second) { + RTC_DCHECK_EQ(first->ssrc, second->ssrc); + return IsNewerSequenceNumber(second->seq_num, first->seq_num); +} + +ForwardErrorCorrection::ReceivedPacket::ReceivedPacket() = default; +ForwardErrorCorrection::ReceivedPacket::~ReceivedPacket() = default; + +ForwardErrorCorrection::RecoveredPacket::RecoveredPacket() = default; +ForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() = default; + +ForwardErrorCorrection::ProtectedPacket::ProtectedPacket() = default; +ForwardErrorCorrection::ProtectedPacket::~ProtectedPacket() = default; + +ForwardErrorCorrection::ReceivedFecPacket::ReceivedFecPacket() = default; +ForwardErrorCorrection::ReceivedFecPacket::~ReceivedFecPacket() = default; + +ForwardErrorCorrection::ForwardErrorCorrection( + std::unique_ptr<FecHeaderReader> fec_header_reader, + std::unique_ptr<FecHeaderWriter> fec_header_writer, + uint32_t ssrc, + uint32_t protected_media_ssrc) + : ssrc_(ssrc), + protected_media_ssrc_(protected_media_ssrc), + fec_header_reader_(std::move(fec_header_reader)), + fec_header_writer_(std::move(fec_header_writer)), + generated_fec_packets_(fec_header_writer_->MaxFecPackets()), + packet_mask_size_(0) {} + +ForwardErrorCorrection::~ForwardErrorCorrection() = default; + +std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateUlpfec( + uint32_t ssrc) { + std::unique_ptr<FecHeaderReader> fec_header_reader(new UlpfecHeaderReader()); + std::unique_ptr<FecHeaderWriter> fec_header_writer(new UlpfecHeaderWriter()); + return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection( + std::move(fec_header_reader), std::move(fec_header_writer), ssrc, ssrc)); +} + +std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateFlexfec( + uint32_t ssrc, + uint32_t protected_media_ssrc) { + std::unique_ptr<FecHeaderReader> fec_header_reader(new FlexfecHeaderReader()); + std::unique_ptr<FecHeaderWriter> fec_header_writer(new FlexfecHeaderWriter()); + return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection( + std::move(fec_header_reader), std::move(fec_header_writer), ssrc, + protected_media_ssrc)); +} + +int ForwardErrorCorrection::EncodeFec(const PacketList& media_packets, + uint8_t protection_factor, + int num_important_packets, + bool use_unequal_protection, + FecMaskType fec_mask_type, + std::list<Packet*>* fec_packets) { + const size_t num_media_packets = media_packets.size(); + + // Sanity check arguments. + RTC_DCHECK_GT(num_media_packets, 0); + RTC_DCHECK_GE(num_important_packets, 0); + RTC_DCHECK_LE(num_important_packets, num_media_packets); + RTC_DCHECK(fec_packets->empty()); + const size_t max_media_packets = fec_header_writer_->MaxMediaPackets(); + if (num_media_packets > max_media_packets) { + RTC_LOG(LS_WARNING) << "Can't protect " << num_media_packets + << " media packets per frame. Max is " + << max_media_packets << "."; + return -1; + } + + // Error check the media packets. + for (const auto& media_packet : media_packets) { + RTC_DCHECK(media_packet); + if (media_packet->length < kRtpHeaderSize) { + RTC_LOG(LS_WARNING) << "Media packet " << media_packet->length + << " bytes " + << "is smaller than RTP header."; + return -1; + } + // Ensure the FEC packets will fit in a typical MTU. + if (media_packet->length + MaxPacketOverhead() + kTransportOverhead > + IP_PACKET_SIZE) { + RTC_LOG(LS_WARNING) << "Media packet " << media_packet->length + << " bytes " + << "with overhead is larger than " << IP_PACKET_SIZE + << " bytes."; + } + } + + // Prepare generated FEC packets. + int num_fec_packets = NumFecPackets(num_media_packets, protection_factor); + if (num_fec_packets == 0) { + return 0; + } + for (int i = 0; i < num_fec_packets; ++i) { + memset(generated_fec_packets_[i].data, 0, IP_PACKET_SIZE); + // Use this as a marker for untouched packets. + generated_fec_packets_[i].length = 0; + fec_packets->push_back(&generated_fec_packets_[i]); + } + + const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); + packet_mask_size_ = internal::PacketMaskSize(num_media_packets); + memset(packet_masks_, 0, num_fec_packets * packet_mask_size_); + internal::GeneratePacketMasks(num_media_packets, num_fec_packets, + num_important_packets, use_unequal_protection, + mask_table, packet_masks_); + + // Adapt packet masks to missing media packets. + int num_mask_bits = InsertZerosInPacketMasks(media_packets, num_fec_packets); + if (num_mask_bits < 0) { + return -1; + } + packet_mask_size_ = internal::PacketMaskSize(num_mask_bits); + + // Write FEC packets to |generated_fec_packets_|. + GenerateFecPayloads(media_packets, num_fec_packets); + // TODO(brandtr): Generalize this when multistream protection support is + // added. + const uint32_t media_ssrc = ParseSsrc(media_packets.front()->data); + const uint16_t seq_num_base = + ParseSequenceNumber(media_packets.front()->data); + FinalizeFecHeaders(num_fec_packets, media_ssrc, seq_num_base); + + return 0; +} + +int ForwardErrorCorrection::NumFecPackets(int num_media_packets, + int protection_factor) { + // Result in Q0 with an unsigned round. + int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8; + // Generate at least one FEC packet if we need protection. + if (protection_factor > 0 && num_fec_packets == 0) { + num_fec_packets = 1; + } + RTC_DCHECK_LE(num_fec_packets, num_media_packets); + return num_fec_packets; +} + +void ForwardErrorCorrection::GenerateFecPayloads( + const PacketList& media_packets, + size_t num_fec_packets) { + RTC_DCHECK(!media_packets.empty()); + for (size_t i = 0; i < num_fec_packets; ++i) { + Packet* const fec_packet = &generated_fec_packets_[i]; + size_t pkt_mask_idx = i * packet_mask_size_; + const size_t min_packet_mask_size = fec_header_writer_->MinPacketMaskSize( + &packet_masks_[pkt_mask_idx], packet_mask_size_); + const size_t fec_header_size = + fec_header_writer_->FecHeaderSize(min_packet_mask_size); + + size_t media_pkt_idx = 0; + auto media_packets_it = media_packets.cbegin(); + uint16_t prev_seq_num = ParseSequenceNumber((*media_packets_it)->data); + while (media_packets_it != media_packets.end()) { + Packet* const media_packet = media_packets_it->get(); + // Should |media_packet| be protected by |fec_packet|? + if (packet_masks_[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) { + size_t media_payload_length = media_packet->length - kRtpHeaderSize; + + bool first_protected_packet = (fec_packet->length == 0); + size_t fec_packet_length = fec_header_size + media_payload_length; + if (fec_packet_length > fec_packet->length) { + // Recall that XORing with zero (which the FEC packets are prefilled + // with) is the identity operator, thus all prior XORs are + // still correct even though we expand the packet length here. + fec_packet->length = fec_packet_length; + } + if (first_protected_packet) { + // Write P, X, CC, M, and PT recovery fields. + // Note that bits 0, 1, and 16 are overwritten in FinalizeFecHeaders. + memcpy(&fec_packet->data[0], &media_packet->data[0], 2); + // Write length recovery field. (This is a temporary location for + // ULPFEC.) + ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2], + media_payload_length); + // Write timestamp recovery field. + memcpy(&fec_packet->data[4], &media_packet->data[4], 4); + // Write payload. + memcpy(&fec_packet->data[fec_header_size], + &media_packet->data[kRtpHeaderSize], media_payload_length); + } else { + XorHeaders(*media_packet, fec_packet); + XorPayloads(*media_packet, media_payload_length, fec_header_size, + fec_packet); + } + } + media_packets_it++; + if (media_packets_it != media_packets.end()) { + uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); + media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); + prev_seq_num = seq_num; + } + pkt_mask_idx += media_pkt_idx / 8; + media_pkt_idx %= 8; + } + RTC_DCHECK_GT(fec_packet->length, 0) + << "Packet mask is wrong or poorly designed."; + } +} + +int ForwardErrorCorrection::InsertZerosInPacketMasks( + const PacketList& media_packets, + size_t num_fec_packets) { + size_t num_media_packets = media_packets.size(); + if (num_media_packets <= 1) { + return num_media_packets; + } + uint16_t last_seq_num = ParseSequenceNumber(media_packets.back()->data); + uint16_t first_seq_num = ParseSequenceNumber(media_packets.front()->data); + size_t total_missing_seq_nums = + static_cast<uint16_t>(last_seq_num - first_seq_num) - num_media_packets + + 1; + if (total_missing_seq_nums == 0) { + // All sequence numbers are covered by the packet mask. + // No zero insertion required. + return num_media_packets; + } + const size_t max_media_packets = fec_header_writer_->MaxMediaPackets(); + if (total_missing_seq_nums + num_media_packets > max_media_packets) { + return -1; + } + // Allocate the new mask. + size_t tmp_packet_mask_size = + internal::PacketMaskSize(total_missing_seq_nums + num_media_packets); + memset(tmp_packet_masks_, 0, num_fec_packets * tmp_packet_mask_size); + + auto media_packets_it = media_packets.cbegin(); + uint16_t prev_seq_num = first_seq_num; + ++media_packets_it; + + // Insert the first column. + internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_, + packet_mask_size_, num_fec_packets, 0, 0); + size_t new_bit_index = 1; + size_t old_bit_index = 1; + // Insert zeros in the bit mask for every hole in the sequence. + while (media_packets_it != media_packets.end()) { + if (new_bit_index == max_media_packets) { + // We can only cover up to 48 packets. + break; + } + uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); + const int num_zeros_to_insert = + static_cast<uint16_t>(seq_num - prev_seq_num - 1); + if (num_zeros_to_insert > 0) { + internal::InsertZeroColumns(num_zeros_to_insert, tmp_packet_masks_, + tmp_packet_mask_size, num_fec_packets, + new_bit_index); + } + new_bit_index += num_zeros_to_insert; + internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_, + packet_mask_size_, num_fec_packets, new_bit_index, + old_bit_index); + ++new_bit_index; + ++old_bit_index; + prev_seq_num = seq_num; + ++media_packets_it; + } + if (new_bit_index % 8 != 0) { + // We didn't fill the last byte. Shift bits to correct position. + for (uint16_t row = 0; row < num_fec_packets; ++row) { + int new_byte_index = row * tmp_packet_mask_size + new_bit_index / 8; + tmp_packet_masks_[new_byte_index] <<= (7 - (new_bit_index % 8)); + } + } + // Replace the old mask with the new. + memcpy(packet_masks_, tmp_packet_masks_, + num_fec_packets * tmp_packet_mask_size); + return new_bit_index; +} + +void ForwardErrorCorrection::FinalizeFecHeaders(size_t num_fec_packets, + uint32_t media_ssrc, + uint16_t seq_num_base) { + for (size_t i = 0; i < num_fec_packets; ++i) { + fec_header_writer_->FinalizeFecHeader( + media_ssrc, seq_num_base, &packet_masks_[i * packet_mask_size_], + packet_mask_size_, &generated_fec_packets_[i]); + } +} + +void ForwardErrorCorrection::ResetState( + RecoveredPacketList* recovered_packets) { + // Free the memory for any existing recovered packets, if the caller hasn't. + recovered_packets->clear(); + received_fec_packets_.clear(); +} + +void ForwardErrorCorrection::InsertMediaPacket( + RecoveredPacketList* recovered_packets, + const ReceivedPacket& received_packet) { + RTC_DCHECK_EQ(received_packet.ssrc, protected_media_ssrc_); + + // Search for duplicate packets. + for (const auto& recovered_packet : *recovered_packets) { + RTC_DCHECK_EQ(recovered_packet->ssrc, received_packet.ssrc); + if (recovered_packet->seq_num == received_packet.seq_num) { + // Duplicate packet, no need to add to list. + return; + } + } + + std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket()); + // This "recovered packet" was not recovered using parity packets. + recovered_packet->was_recovered = false; + // This media packet has already been passed on. + recovered_packet->returned = true; + recovered_packet->ssrc = received_packet.ssrc; + recovered_packet->seq_num = received_packet.seq_num; + recovered_packet->pkt = received_packet.pkt; + recovered_packet->pkt->length = received_packet.pkt->length; + // TODO(holmer): Consider replacing this with a binary search for the right + // position, and then just insert the new packet. Would get rid of the sort. + RecoveredPacket* recovered_packet_ptr = recovered_packet.get(); + recovered_packets->push_back(std::move(recovered_packet)); + recovered_packets->sort(SortablePacket::LessThan()); + UpdateCoveringFecPackets(*recovered_packet_ptr); +} + +void ForwardErrorCorrection::UpdateCoveringFecPackets( + const RecoveredPacket& packet) { + for (auto& fec_packet : received_fec_packets_) { + // Is this FEC packet protecting the media packet |packet|? + auto protected_it = std::lower_bound(fec_packet->protected_packets.begin(), + fec_packet->protected_packets.end(), + &packet, SortablePacket::LessThan()); + if (protected_it != fec_packet->protected_packets.end() && + (*protected_it)->seq_num == packet.seq_num) { + // Found an FEC packet which is protecting |packet|. + (*protected_it)->pkt = packet.pkt; + } + } +} + +void ForwardErrorCorrection::InsertFecPacket( + const RecoveredPacketList& recovered_packets, + const ReceivedPacket& received_packet) { + RTC_DCHECK_EQ(received_packet.ssrc, ssrc_); + + // Check for duplicate. + for (const auto& existing_fec_packet : received_fec_packets_) { + RTC_DCHECK_EQ(existing_fec_packet->ssrc, received_packet.ssrc); + if (existing_fec_packet->seq_num == received_packet.seq_num) { + // Drop duplicate FEC packet data. + return; + } + } + + std::unique_ptr<ReceivedFecPacket> fec_packet(new ReceivedFecPacket()); + fec_packet->pkt = received_packet.pkt; + fec_packet->ssrc = received_packet.ssrc; + fec_packet->seq_num = received_packet.seq_num; + // Parse ULPFEC/FlexFEC header specific info. + bool ret = fec_header_reader_->ReadFecHeader(fec_packet.get()); + if (!ret) { + return; + } + + // TODO(brandtr): Update here when we support multistream protection. + if (fec_packet->protected_ssrc != protected_media_ssrc_) { + RTC_LOG(LS_INFO) + << "Received FEC packet is protecting an unknown media SSRC; dropping."; + return; + } + + // Parse packet mask from header and represent as protected packets. + for (uint16_t byte_idx = 0; byte_idx < fec_packet->packet_mask_size; + ++byte_idx) { + uint8_t packet_mask = + fec_packet->pkt->data[fec_packet->packet_mask_offset + byte_idx]; + for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) { + if (packet_mask & (1 << (7 - bit_idx))) { + std::unique_ptr<ProtectedPacket> protected_packet( + new ProtectedPacket()); + // This wraps naturally with the sequence number. + protected_packet->ssrc = protected_media_ssrc_; + protected_packet->seq_num = static_cast<uint16_t>( + fec_packet->seq_num_base + (byte_idx << 3) + bit_idx); + protected_packet->pkt = nullptr; + fec_packet->protected_packets.push_back(std::move(protected_packet)); + } + } + } + + if (fec_packet->protected_packets.empty()) { + // All-zero packet mask; we can discard this FEC packet. + RTC_LOG(LS_WARNING) << "Received FEC packet has an all-zero packet mask."; + } else { + AssignRecoveredPackets(recovered_packets, fec_packet.get()); + // TODO(holmer): Consider replacing this with a binary search for the right + // position, and then just insert the new packet. Would get rid of the sort. + received_fec_packets_.push_back(std::move(fec_packet)); + received_fec_packets_.sort(SortablePacket::LessThan()); + const size_t max_fec_packets = fec_header_reader_->MaxFecPackets(); + if (received_fec_packets_.size() > max_fec_packets) { + received_fec_packets_.pop_front(); + } + RTC_DCHECK_LE(received_fec_packets_.size(), max_fec_packets); + } +} + +void ForwardErrorCorrection::AssignRecoveredPackets( + const RecoveredPacketList& recovered_packets, + ReceivedFecPacket* fec_packet) { + ProtectedPacketList* protected_packets = &fec_packet->protected_packets; + std::vector<RecoveredPacket*> recovered_protected_packets; + + // Find intersection between the (sorted) containers |protected_packets| + // and |recovered_packets|, i.e. all protected packets that have already + // been recovered. Update the corresponding protected packets to point to + // the recovered packets. + auto it_p = protected_packets->cbegin(); + auto it_r = recovered_packets.cbegin(); + SortablePacket::LessThan less_than; + while (it_p != protected_packets->end() && it_r != recovered_packets.end()) { + if (less_than(*it_p, *it_r)) { + ++it_p; + } else if (less_than(*it_r, *it_p)) { + ++it_r; + } else { // *it_p == *it_r. + // This protected packet has already been recovered. + (*it_p)->pkt = (*it_r)->pkt; + ++it_p; + ++it_r; + } + } +} + +void ForwardErrorCorrection::InsertPacket( + const ReceivedPacket& received_packet, + RecoveredPacketList* recovered_packets) { + // Discard old FEC packets such that the sequence numbers in + // |received_fec_packets_| span at most 1/2 of the sequence number space. + // This is important for keeping |received_fec_packets_| sorted, and may + // also reduce the possibility of incorrect decoding due to sequence number + // wrap-around. + // TODO(marpan/holmer): We should be able to improve detection/discarding of + // old FEC packets based on timestamp information or better sequence number + // thresholding (e.g., to distinguish between wrap-around and reordering). + if (!received_fec_packets_.empty() && + received_packet.ssrc == received_fec_packets_.front()->ssrc) { + // It only makes sense to detect wrap-around when |received_packet| + // and |front_received_fec_packet| belong to the same sequence number + // space, i.e., the same SSRC. This happens when |received_packet| + // is a FEC packet, or if |received_packet| is a media packet and + // RED+ULPFEC is used. + auto it = received_fec_packets_.begin(); + while (it != received_fec_packets_.end()) { + uint16_t seq_num_diff = MinDiff(received_packet.seq_num, (*it)->seq_num); + if (seq_num_diff > 0x3fff) { + it = received_fec_packets_.erase(it); + } else { + // No need to keep iterating, since |received_fec_packets_| is sorted. + break; + } + } + } + + if (received_packet.is_fec) { + InsertFecPacket(*recovered_packets, received_packet); + } else { + InsertMediaPacket(recovered_packets, received_packet); + } + + DiscardOldRecoveredPackets(recovered_packets); +} + +bool ForwardErrorCorrection::StartPacketRecovery( + const ReceivedFecPacket& fec_packet, + RecoveredPacket* recovered_packet) { + // Sanity check packet length. + if (fec_packet.pkt->length < fec_packet.fec_header_size) { + RTC_LOG(LS_WARNING) + << "The FEC packet is truncated: it does not contain enough room " + << "for its own header."; + return false; + } + // Initialize recovered packet data. + recovered_packet->pkt = new Packet(); + memset(recovered_packet->pkt->data, 0, IP_PACKET_SIZE); + recovered_packet->returned = false; + recovered_packet->was_recovered = true; + // Copy bytes corresponding to minimum RTP header size. + // Note that the sequence number and SSRC fields will be overwritten + // at the end of packet recovery. + memcpy(&recovered_packet->pkt->data, fec_packet.pkt->data, kRtpHeaderSize); + // Copy remaining FEC payload. + if (fec_packet.protection_length > + std::min(sizeof(recovered_packet->pkt->data) - kRtpHeaderSize, + sizeof(fec_packet.pkt->data) - fec_packet.fec_header_size)) { + RTC_LOG(LS_WARNING) << "Incorrect protection length, dropping FEC packet."; + return false; + } + memcpy(&recovered_packet->pkt->data[kRtpHeaderSize], + &fec_packet.pkt->data[fec_packet.fec_header_size], + fec_packet.protection_length); + return true; +} + +bool ForwardErrorCorrection::FinishPacketRecovery( + const ReceivedFecPacket& fec_packet, + RecoveredPacket* recovered_packet) { + // Set the RTP version to 2. + recovered_packet->pkt->data[0] |= 0x80; // Set the 1st bit. + recovered_packet->pkt->data[0] &= 0xbf; // Clear the 2nd bit. + // Recover the packet length, from temporary location. + recovered_packet->pkt->length = + ByteReader<uint16_t>::ReadBigEndian(&recovered_packet->pkt->data[2]) + + kRtpHeaderSize; + if (recovered_packet->pkt->length > + sizeof(recovered_packet->pkt->data) - kRtpHeaderSize) { + RTC_LOG(LS_WARNING) << "The recovered packet had a length larger than a " + << "typical IP packet, and is thus dropped."; + return false; + } + // Set the SN field. + ByteWriter<uint16_t>::WriteBigEndian(&recovered_packet->pkt->data[2], + recovered_packet->seq_num); + // Set the SSRC field. + ByteWriter<uint32_t>::WriteBigEndian(&recovered_packet->pkt->data[8], + fec_packet.protected_ssrc); + recovered_packet->ssrc = fec_packet.protected_ssrc; + return true; +} + +void ForwardErrorCorrection::XorHeaders(const Packet& src, Packet* dst) { + // XOR the first 2 bytes of the header: V, P, X, CC, M, PT fields. + dst->data[0] ^= src.data[0]; + dst->data[1] ^= src.data[1]; + + // XOR the length recovery field. + uint8_t src_payload_length_network_order[2]; + ByteWriter<uint16_t>::WriteBigEndian(src_payload_length_network_order, + src.length - kRtpHeaderSize); + dst->data[2] ^= src_payload_length_network_order[0]; + dst->data[3] ^= src_payload_length_network_order[1]; + + // XOR the 5th to 8th bytes of the header: the timestamp field. + dst->data[4] ^= src.data[4]; + dst->data[5] ^= src.data[5]; + dst->data[6] ^= src.data[6]; + dst->data[7] ^= src.data[7]; + + // Skip the 9th to 12th bytes of the header. +} + +void ForwardErrorCorrection::XorPayloads(const Packet& src, + size_t payload_length, + size_t dst_offset, + Packet* dst) { + // XOR the payload. + RTC_DCHECK_LE(kRtpHeaderSize + payload_length, sizeof(src.data)); + RTC_DCHECK_LE(dst_offset + payload_length, sizeof(dst->data)); + for (size_t i = 0; i < payload_length; ++i) { + dst->data[dst_offset + i] ^= src.data[kRtpHeaderSize + i]; + } +} + +bool ForwardErrorCorrection::RecoverPacket(const ReceivedFecPacket& fec_packet, + RecoveredPacket* recovered_packet) { + if (!StartPacketRecovery(fec_packet, recovered_packet)) { + return false; + } + for (const auto& protected_packet : fec_packet.protected_packets) { + if (protected_packet->pkt == nullptr) { + // This is the packet we're recovering. + recovered_packet->seq_num = protected_packet->seq_num; + } else { + XorHeaders(*protected_packet->pkt, recovered_packet->pkt); + XorPayloads(*protected_packet->pkt, protected_packet->pkt->length, + kRtpHeaderSize, recovered_packet->pkt); + } + } + if (!FinishPacketRecovery(fec_packet, recovered_packet)) { + return false; + } + return true; +} + +void ForwardErrorCorrection::AttemptRecovery( + RecoveredPacketList* recovered_packets) { + auto fec_packet_it = received_fec_packets_.begin(); + while (fec_packet_it != received_fec_packets_.end()) { + // Search for each FEC packet's protected media packets. + int packets_missing = NumCoveredPacketsMissing(**fec_packet_it); + + // We can only recover one packet with an FEC packet. + if (packets_missing == 1) { + // Recovery possible. + std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket()); + recovered_packet->pkt = nullptr; + if (!RecoverPacket(**fec_packet_it, recovered_packet.get())) { + // Can't recover using this packet, drop it. + fec_packet_it = received_fec_packets_.erase(fec_packet_it); + continue; + } + + auto recovered_packet_ptr = recovered_packet.get(); + // Add recovered packet to the list of recovered packets and update any + // FEC packets covering this packet with a pointer to the data. + // TODO(holmer): Consider replacing this with a binary search for the + // right position, and then just insert the new packet. Would get rid of + // the sort. + recovered_packets->push_back(std::move(recovered_packet)); + recovered_packets->sort(SortablePacket::LessThan()); + UpdateCoveringFecPackets(*recovered_packet_ptr); + DiscardOldRecoveredPackets(recovered_packets); + fec_packet_it = received_fec_packets_.erase(fec_packet_it); + + // A packet has been recovered. We need to check the FEC list again, as + // this may allow additional packets to be recovered. + // Restart for first FEC packet. + fec_packet_it = received_fec_packets_.begin(); + } else if (packets_missing == 0) { + // Either all protected packets arrived or have been recovered. We can + // discard this FEC packet. + fec_packet_it = received_fec_packets_.erase(fec_packet_it); + } else { + fec_packet_it++; + } + } +} + +int ForwardErrorCorrection::NumCoveredPacketsMissing( + const ReceivedFecPacket& fec_packet) { + int packets_missing = 0; + for (const auto& protected_packet : fec_packet.protected_packets) { + if (protected_packet->pkt == nullptr) { + ++packets_missing; + if (packets_missing > 1) { + break; // We can't recover more than one packet. + } + } + } + return packets_missing; +} + +void ForwardErrorCorrection::DiscardOldRecoveredPackets( + RecoveredPacketList* recovered_packets) { + const size_t max_media_packets = fec_header_reader_->MaxMediaPackets(); + while (recovered_packets->size() > max_media_packets) { + recovered_packets->pop_front(); + } + RTC_DCHECK_LE(recovered_packets->size(), max_media_packets); +} + +uint16_t ForwardErrorCorrection::ParseSequenceNumber(uint8_t* packet) { + return (packet[2] << 8) + packet[3]; +} + +uint32_t ForwardErrorCorrection::ParseSsrc(uint8_t* packet) { + return (packet[8] << 24) + (packet[9] << 16) + (packet[10] << 8) + packet[11]; +} + +void ForwardErrorCorrection::DecodeFec(const ReceivedPacket& received_packet, + RecoveredPacketList* recovered_packets) { + RTC_DCHECK(recovered_packets); + + const size_t max_media_packets = fec_header_reader_->MaxMediaPackets(); + if (recovered_packets->size() == max_media_packets) { + const RecoveredPacket* back_recovered_packet = + recovered_packets->back().get(); + + if (received_packet.ssrc == back_recovered_packet->ssrc) { + const unsigned int seq_num_diff = + MinDiff(received_packet.seq_num, back_recovered_packet->seq_num); + if (seq_num_diff > max_media_packets) { + // A big gap in sequence numbers. The old recovered packets + // are now useless, so it's safe to do a reset. + RTC_LOG(LS_INFO) << "Big gap in media/ULPFEC sequence numbers. No need " + "to keep the old packets in the FEC buffers, thus " + "resetting them."; + ResetState(recovered_packets); + } + } + } + + InsertPacket(received_packet, recovered_packets); + AttemptRecovery(recovered_packets); +} + +size_t ForwardErrorCorrection::MaxPacketOverhead() const { + return fec_header_writer_->MaxPacketOverhead(); +} + +FecHeaderReader::FecHeaderReader(size_t max_media_packets, + size_t max_fec_packets) + : max_media_packets_(max_media_packets), + max_fec_packets_(max_fec_packets) {} + +FecHeaderReader::~FecHeaderReader() = default; + +size_t FecHeaderReader::MaxMediaPackets() const { + return max_media_packets_; +} + +size_t FecHeaderReader::MaxFecPackets() const { + return max_fec_packets_; +} + +FecHeaderWriter::FecHeaderWriter(size_t max_media_packets, + size_t max_fec_packets, + size_t max_packet_overhead) + : max_media_packets_(max_media_packets), + max_fec_packets_(max_fec_packets), + max_packet_overhead_(max_packet_overhead) {} + +FecHeaderWriter::~FecHeaderWriter() = default; + +size_t FecHeaderWriter::MaxMediaPackets() const { + return max_media_packets_; +} + +size_t FecHeaderWriter::MaxFecPackets() const { + return max_fec_packets_; +} + +size_t FecHeaderWriter::MaxPacketOverhead() const { + return max_packet_overhead_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.h new file mode 100644 index 0000000000..97acb393f3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.h @@ -0,0 +1,419 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_ +#define MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_ + +#include <stdint.h> + +#include <list> +#include <memory> +#include <vector> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/refcount.h" +#include "rtc_base/scoped_ref_ptr.h" + +namespace webrtc { + +class FecHeaderReader; +class FecHeaderWriter; + +// Performs codec-independent forward error correction (FEC), based on RFC 5109. +// Option exists to enable unequal protection (UEP) across packets. +// This is not to be confused with protection within packets +// (referred to as uneven level protection (ULP) in RFC 5109). +// TODO(brandtr): Split this class into a separate encoder +// and a separate decoder. +class ForwardErrorCorrection { + public: + // TODO(holmer): As a next step all these struct-like packet classes should be + // refactored into proper classes, and their members should be made private. + // This will require parts of the functionality in forward_error_correction.cc + // and receiver_fec.cc to be refactored into the packet classes. + class Packet { + public: + Packet(); + virtual ~Packet(); + + // Add a reference. + virtual int32_t AddRef(); + + // Release a reference. Will delete the object if the reference count + // reaches zero. + virtual int32_t Release(); + + size_t length; // Length of packet in bytes. + uint8_t data[IP_PACKET_SIZE]; // Packet data. + + private: + int32_t ref_count_; // Counts the number of references to a packet. + }; + + // TODO(holmer): Refactor into a proper class. + class SortablePacket { + public: + // Functor which returns true if the sequence number of |first| + // is < the sequence number of |second|. Should only ever be called for + // packets belonging to the same SSRC. + struct LessThan { + template <typename S, typename T> + bool operator() (const S& first, const T& second); + }; + + uint32_t ssrc; + uint16_t seq_num; + }; + + // Used for the input to DecodeFec(). + // + // TODO(nisse): Delete class, instead passing |is_fec| and |pkt| as separate + // arguments. + class ReceivedPacket : public SortablePacket { + public: + ReceivedPacket(); + ~ReceivedPacket(); + + bool is_fec; // Set to true if this is an FEC packet and false + // otherwise. + rtc::scoped_refptr<Packet> pkt; // Pointer to the packet storage. + }; + + // The recovered list parameter of DecodeFec() references structs of + // this type. + // TODO(holmer): Refactor into a proper class. + class RecoveredPacket : public SortablePacket { + public: + RecoveredPacket(); + ~RecoveredPacket(); + + bool was_recovered; // Will be true if this packet was recovered by + // the FEC. Otherwise it was a media packet passed in + // through the received packet list. + bool returned; // True when the packet already has been returned to the + // caller through the callback. + rtc::scoped_refptr<Packet> pkt; // Pointer to the packet storage. + }; + + // Used to link media packets to their protecting FEC packets. + // + // TODO(holmer): Refactor into a proper class. + class ProtectedPacket : public SortablePacket { + public: + ProtectedPacket(); + ~ProtectedPacket(); + + rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt; + }; + + using ProtectedPacketList = std::list<std::unique_ptr<ProtectedPacket>>; + + // Used for internal storage of received FEC packets in a list. + // + // TODO(holmer): Refactor into a proper class. + class ReceivedFecPacket : public SortablePacket { + public: + ReceivedFecPacket(); + ~ReceivedFecPacket(); + + // List of media packets that this FEC packet protects. + ProtectedPacketList protected_packets; + // RTP header fields. + uint32_t ssrc; + // FEC header fields. + size_t fec_header_size; + uint32_t protected_ssrc; + uint16_t seq_num_base; + size_t packet_mask_offset; // Relative start of FEC header. + size_t packet_mask_size; + size_t protection_length; + // Raw data. + rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt; + }; + + using PacketList = std::list<std::unique_ptr<Packet>>; + using RecoveredPacketList = std::list<std::unique_ptr<RecoveredPacket>>; + using ReceivedFecPacketList = std::list<std::unique_ptr<ReceivedFecPacket>>; + + ~ForwardErrorCorrection(); + + // Creates a ForwardErrorCorrection tailored for a specific FEC scheme. + static std::unique_ptr<ForwardErrorCorrection> CreateUlpfec(uint32_t ssrc); + static std::unique_ptr<ForwardErrorCorrection> CreateFlexfec( + uint32_t ssrc, + uint32_t protected_media_ssrc); + + // Generates a list of FEC packets from supplied media packets. + // + // Input: media_packets List of media packets to protect, of type + // Packet. All packets must belong to the + // same frame and the list must not be empty. + // Input: protection_factor FEC protection overhead in the [0, 255] + // domain. To obtain 100% overhead, or an + // equal number of FEC packets as + // media packets, use 255. + // Input: num_important_packets The number of "important" packets in the + // frame. These packets may receive greater + // protection than the remaining packets. + // The important packets must be located at the + // start of the media packet list. For codecs + // with data partitioning, the important + // packets may correspond to first partition + // packets. + // Input: use_unequal_protection Parameter to enable/disable unequal + // protection (UEP) across packets. Enabling + // UEP will allocate more protection to the + // num_important_packets from the start of the + // media_packets. + // Input: fec_mask_type The type of packet mask used in the FEC. + // Random or bursty type may be selected. The + // bursty type is only defined up to 12 media + // packets. If the number of media packets is + // above 12, the packet masks from the random + // table will be selected. + // Output: fec_packets List of pointers to generated FEC packets, + // of type Packet. Must be empty on entry. + // The memory available through the list will + // be valid until the next call to + // EncodeFec(). + // + // Returns 0 on success, -1 on failure. + // + int EncodeFec(const PacketList& media_packets, + uint8_t protection_factor, + int num_important_packets, + bool use_unequal_protection, + FecMaskType fec_mask_type, + std::list<Packet*>* fec_packets); + + // Decodes a list of received media and FEC packets. It will parse the + // |received_packets|, storing FEC packets internally, and move + // media packets to |recovered_packets|. The recovered list will be + // sorted by ascending sequence number and have duplicates removed. + // The function should be called as new packets arrive, and + // |recovered_packets| will be progressively assembled with each call. + // When the function returns, |received_packets| will be empty. + // + // The caller will allocate packets submitted through |received_packets|. + // The function will handle allocation of recovered packets. + // + // Input: received_packets List of new received packets, of type + // ReceivedPacket, belonging to a single + // frame. At output the list will be empty, + // with packets either stored internally, + // or accessible through the recovered list. + // Output: recovered_packets List of recovered media packets, of type + // RecoveredPacket, belonging to a single + // frame. The memory available through the + // list will be valid until the next call to + // DecodeFec(). + // + void DecodeFec(const ReceivedPacket& received_packet, + RecoveredPacketList* recovered_packets); + + // Get the number of generated FEC packets, given the number of media packets + // and the protection factor. + static int NumFecPackets(int num_media_packets, int protection_factor); + + // Gets the maximum size of the FEC headers in bytes, which must be + // accounted for as packet overhead. + size_t MaxPacketOverhead() const; + + // Reset internal states from last frame and clear |recovered_packets|. + // Frees all memory allocated by this class. + void ResetState(RecoveredPacketList* recovered_packets); + + // TODO(brandtr): Remove these functions when the Packet classes + // have been refactored. + static uint16_t ParseSequenceNumber(uint8_t* packet); + static uint32_t ParseSsrc(uint8_t* packet); + + protected: + ForwardErrorCorrection(std::unique_ptr<FecHeaderReader> fec_header_reader, + std::unique_ptr<FecHeaderWriter> fec_header_writer, + uint32_t ssrc, + uint32_t protected_media_ssrc); + + private: + // Analyzes |media_packets| for holes in the sequence and inserts zero columns + // into the |packet_mask| where those holes are found. Zero columns means that + // those packets will have no protection. + // Returns the number of bits used for one row of the new packet mask. + // Requires that |packet_mask| has at least 6 * |num_fec_packets| bytes + // allocated. + int InsertZerosInPacketMasks(const PacketList& media_packets, + size_t num_fec_packets); + + // Writes FEC payloads and some recovery fields in the FEC headers. + void GenerateFecPayloads(const PacketList& media_packets, + size_t num_fec_packets); + + // Writes the FEC header fields that are not written by GenerateFecPayloads. + // This includes writing the packet masks. + void FinalizeFecHeaders(size_t num_fec_packets, + uint32_t media_ssrc, + uint16_t seq_num_base); + + // Inserts the |received_packet| into the internal received FEC packet list + // or into |recovered_packets|. + void InsertPacket(const ReceivedPacket& received_packet, + RecoveredPacketList* recovered_packets); + + // Inserts the |received_packet| into |recovered_packets|. Deletes duplicates. + void InsertMediaPacket(RecoveredPacketList* recovered_packets, + const ReceivedPacket& received_packet); + + // Assigns pointers to the recovered packet from all FEC packets which cover + // it. + // Note: This reduces the complexity when we want to try to recover a packet + // since we don't have to find the intersection between recovered packets and + // packets covered by the FEC packet. + void UpdateCoveringFecPackets(const RecoveredPacket& packet); + + // Insert |received_packet| into internal FEC list. Deletes duplicates. + void InsertFecPacket(const RecoveredPacketList& recovered_packets, + const ReceivedPacket& received_packet); + + // Assigns pointers to already recovered packets covered by |fec_packet|. + static void AssignRecoveredPackets( + const RecoveredPacketList& recovered_packets, + ReceivedFecPacket* fec_packet); + + // Attempt to recover missing packets, using the internally stored + // received FEC packets. + void AttemptRecovery(RecoveredPacketList* recovered_packets); + + // Initializes headers and payload before the XOR operation + // that recovers a packet. + static bool StartPacketRecovery(const ReceivedFecPacket& fec_packet, + RecoveredPacket* recovered_packet); + + // Performs XOR between the first 8 bytes of |src| and |dst| and stores + // the result in |dst|. The 3rd and 4th bytes are used for storing + // the length recovery field. + static void XorHeaders(const Packet& src, Packet* dst); + + // Performs XOR between the payloads of |src| and |dst| and stores the result + // in |dst|. The parameter |dst_offset| determines at what byte the + // XOR operation starts in |dst|. In total, |payload_length| bytes are XORed. + static void XorPayloads(const Packet& src, + size_t payload_length, + size_t dst_offset, + Packet* dst); + + // Finalizes recovery of packet by setting RTP header fields. + // This is not specific to the FEC scheme used. + static bool FinishPacketRecovery(const ReceivedFecPacket& fec_packet, + RecoveredPacket* recovered_packet); + + // Recover a missing packet. + static bool RecoverPacket(const ReceivedFecPacket& fec_packet, + RecoveredPacket* recovered_packet); + + // Get the number of missing media packets which are covered by |fec_packet|. + // An FEC packet can recover at most one packet, and if zero packets are + // missing the FEC packet can be discarded. This function returns 2 when two + // or more packets are missing. + static int NumCoveredPacketsMissing(const ReceivedFecPacket& fec_packet); + + // Discards old packets in |recovered_packets|, which are no longer relevant + // for recovering lost packets. + void DiscardOldRecoveredPackets(RecoveredPacketList* recovered_packets); + + // These SSRCs are only used by the decoder. + const uint32_t ssrc_; + const uint32_t protected_media_ssrc_; + + std::unique_ptr<FecHeaderReader> fec_header_reader_; + std::unique_ptr<FecHeaderWriter> fec_header_writer_; + + std::vector<Packet> generated_fec_packets_; + ReceivedFecPacketList received_fec_packets_; + + // Arrays used to avoid dynamically allocating memory when generating + // the packet masks. + // (There are never more than |kUlpfecMaxMediaPackets| FEC packets generated.) + uint8_t packet_masks_[kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize]; + uint8_t tmp_packet_masks_[kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize]; + size_t packet_mask_size_; +}; + +// Classes derived from FecHeader{Reader,Writer} encapsulate the +// specifics of reading and writing FEC header for, e.g., ULPFEC +// and FlexFEC. +class FecHeaderReader { + public: + virtual ~FecHeaderReader(); + + // The maximum number of media packets that can be covered by one FEC packet. + size_t MaxMediaPackets() const; + + // The maximum number of FEC packets that is supported, per call + // to ForwardErrorCorrection::EncodeFec(). + size_t MaxFecPackets() const; + + // Parses FEC header and stores information in ReceivedFecPacket members. + virtual bool ReadFecHeader( + ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const = 0; + + protected: + FecHeaderReader(size_t max_media_packets, size_t max_fec_packets); + + const size_t max_media_packets_; + const size_t max_fec_packets_; +}; + +class FecHeaderWriter { + public: + virtual ~FecHeaderWriter(); + + // The maximum number of media packets that can be covered by one FEC packet. + size_t MaxMediaPackets() const; + + // The maximum number of FEC packets that is supported, per call + // to ForwardErrorCorrection::EncodeFec(). + size_t MaxFecPackets() const; + + // The maximum overhead (in bytes) per packet, due to FEC headers. + size_t MaxPacketOverhead() const; + + // Calculates the minimum packet mask size needed (in bytes), + // given the discrete options of the ULPFEC masks and the bits + // set in the current packet mask. + virtual size_t MinPacketMaskSize(const uint8_t* packet_mask, + size_t packet_mask_size) const = 0; + + // The header size (in bytes), given the packet mask size. + virtual size_t FecHeaderSize(size_t packet_mask_size) const = 0; + + // Writes FEC header. + virtual void FinalizeFecHeader( + uint32_t media_ssrc, + uint16_t seq_num_base, + const uint8_t* packet_mask, + size_t packet_mask_size, + ForwardErrorCorrection::Packet* fec_packet) const = 0; + + protected: + FecHeaderWriter(size_t max_media_packets, + size_t max_fec_packets, + size_t max_packet_overhead); + + const size_t max_media_packets_; + const size_t max_fec_packets_; + const size_t max_packet_overhead_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.cc new file mode 100644 index 0000000000..60b403bb78 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.cc @@ -0,0 +1,433 @@ +/* + * 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 "modules/rtp_rtcp/source/forward_error_correction_internal.h" + +#include <assert.h> +#include <string.h> + +#include <algorithm> + +#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h" +#include "modules/rtp_rtcp/source/fec_private_tables_random.h" +#include "rtc_base/checks.h" + +namespace { +using webrtc::fec_private_tables::kPacketMaskBurstyTbl; +using webrtc::fec_private_tables::kPacketMaskRandomTbl; + +// Allow for different modes of protection for packets in UEP case. +enum ProtectionMode { + kModeNoOverlap, + kModeOverlap, + kModeBiasFirstPacket, +}; + +// Fits an input mask (sub_mask) to an output mask. +// The mask is a matrix where the rows are the FEC packets, +// and the columns are the source packets the FEC is applied to. +// Each row of the mask is represented by a number of mask bytes. +// +// \param[in] num_mask_bytes The number of mask bytes of output mask. +// \param[in] num_sub_mask_bytes The number of mask bytes of input mask. +// \param[in] num_rows The number of rows of the input mask. +// \param[in] sub_mask A pointer to hold the input mask, of size +// [0, num_rows * num_sub_mask_bytes] +// \param[out] packet_mask A pointer to hold the output mask, of size +// [0, x * num_mask_bytes], where x >= num_rows. +void FitSubMask(int num_mask_bytes, + int num_sub_mask_bytes, + int num_rows, + const uint8_t* sub_mask, + uint8_t* packet_mask) { + if (num_mask_bytes == num_sub_mask_bytes) { + memcpy(packet_mask, sub_mask, num_rows * num_sub_mask_bytes); + } else { + for (int i = 0; i < num_rows; ++i) { + int pkt_mask_idx = i * num_mask_bytes; + int pkt_mask_idx2 = i * num_sub_mask_bytes; + for (int j = 0; j < num_sub_mask_bytes; ++j) { + packet_mask[pkt_mask_idx] = sub_mask[pkt_mask_idx2]; + pkt_mask_idx++; + pkt_mask_idx2++; + } + } + } +} + +// Shifts a mask by number of columns (bits), and fits it to an output mask. +// The mask is a matrix where the rows are the FEC packets, +// and the columns are the source packets the FEC is applied to. +// Each row of the mask is represented by a number of mask bytes. +// +// \param[in] num_mask_bytes The number of mask bytes of output mask. +// \param[in] num_sub_mask_bytes The number of mask bytes of input mask. +// \param[in] num_column_shift The number columns to be shifted, and +// the starting row for the output mask. +// \param[in] end_row The ending row for the output mask. +// \param[in] sub_mask A pointer to hold the input mask, of size +// [0, (end_row_fec - start_row_fec) * +// num_sub_mask_bytes] +// \param[out] packet_mask A pointer to hold the output mask, of size +// [0, x * num_mask_bytes], +// where x >= end_row_fec. +// TODO(marpan): This function is doing three things at the same time: +// shift within a byte, byte shift and resizing. +// Split up into subroutines. +void ShiftFitSubMask(int num_mask_bytes, + int res_mask_bytes, + int num_column_shift, + int end_row, + const uint8_t* sub_mask, + uint8_t* packet_mask) { + // Number of bit shifts within a byte + const int num_bit_shifts = (num_column_shift % 8); + const int num_byte_shifts = num_column_shift >> 3; + + // Modify new mask with sub-mask21. + + // Loop over the remaining FEC packets. + for (int i = num_column_shift; i < end_row; ++i) { + // Byte index of new mask, for row i and column res_mask_bytes, + // offset by the number of bytes shifts + int pkt_mask_idx = + i * num_mask_bytes + res_mask_bytes - 1 + num_byte_shifts; + // Byte index of sub_mask, for row i and column res_mask_bytes + int pkt_mask_idx2 = + (i - num_column_shift) * res_mask_bytes + res_mask_bytes - 1; + + uint8_t shift_right_curr_byte = 0; + uint8_t shift_left_prev_byte = 0; + uint8_t comb_new_byte = 0; + + // Handle case of num_mask_bytes > res_mask_bytes: + // For a given row, copy the rightmost "numBitShifts" bits + // of the last byte of sub_mask into output mask. + if (num_mask_bytes > res_mask_bytes) { + shift_left_prev_byte = (sub_mask[pkt_mask_idx2] << (8 - num_bit_shifts)); + packet_mask[pkt_mask_idx + 1] = shift_left_prev_byte; + } + + // For each row i (FEC packet), shift the bit-mask of the sub_mask. + // Each row of the mask contains "resMaskBytes" of bytes. + // We start from the last byte of the sub_mask and move to first one. + for (int j = res_mask_bytes - 1; j > 0; j--) { + // Shift current byte of sub21 to the right by "numBitShifts". + shift_right_curr_byte = sub_mask[pkt_mask_idx2] >> num_bit_shifts; + + // Fill in shifted bits with bits from the previous (left) byte: + // First shift the previous byte to the left by "8-numBitShifts". + shift_left_prev_byte = + (sub_mask[pkt_mask_idx2 - 1] << (8 - num_bit_shifts)); + + // Then combine both shifted bytes into new mask byte. + comb_new_byte = shift_right_curr_byte | shift_left_prev_byte; + + // Assign to new mask. + packet_mask[pkt_mask_idx] = comb_new_byte; + pkt_mask_idx--; + pkt_mask_idx2--; + } + // For the first byte in the row (j=0 case). + shift_right_curr_byte = sub_mask[pkt_mask_idx2] >> num_bit_shifts; + packet_mask[pkt_mask_idx] = shift_right_curr_byte; + } +} +} // namespace + +namespace webrtc { +namespace internal { + +PacketMaskTable::PacketMaskTable(FecMaskType fec_mask_type, + int num_media_packets) + : fec_mask_type_(InitMaskType(fec_mask_type, num_media_packets)), + fec_packet_mask_table_(InitMaskTable(fec_mask_type_)) {} + +// Sets |fec_mask_type_| to the type of packet mask selected. The type of +// packet mask selected is based on |fec_mask_type| and |num_media_packets|. +// If |num_media_packets| is larger than the maximum allowed by |fec_mask_type| +// for the bursty type, then the random type is selected. +FecMaskType PacketMaskTable::InitMaskType(FecMaskType fec_mask_type, + int num_media_packets) { + // The mask should not be bigger than |packetMaskTbl|. + assert(num_media_packets <= static_cast<int>(sizeof(kPacketMaskRandomTbl) / + sizeof(*kPacketMaskRandomTbl))); + switch (fec_mask_type) { + case kFecMaskRandom: { + return kFecMaskRandom; + } + case kFecMaskBursty: { + int max_media_packets = static_cast<int>(sizeof(kPacketMaskBurstyTbl) / + sizeof(*kPacketMaskBurstyTbl)); + if (num_media_packets > max_media_packets) { + return kFecMaskRandom; + } else { + return kFecMaskBursty; + } + } + } + assert(false); + return kFecMaskRandom; +} + +// Returns the pointer to the packet mask tables corresponding to type +// |fec_mask_type|. +const uint8_t* const* const* PacketMaskTable::InitMaskTable( + FecMaskType fec_mask_type) { + switch (fec_mask_type) { + case kFecMaskRandom: { + return kPacketMaskRandomTbl; + } + case kFecMaskBursty: { + return kPacketMaskBurstyTbl; + } + } + assert(false); + return kPacketMaskRandomTbl; +} + +// Remaining protection after important (first partition) packet protection +void RemainingPacketProtection(int num_media_packets, + int num_fec_remaining, + int num_fec_for_imp_packets, + int num_mask_bytes, + ProtectionMode mode, + uint8_t* packet_mask, + const PacketMaskTable& mask_table) { + if (mode == kModeNoOverlap) { + // sub_mask21 + + const int res_mask_bytes = + PacketMaskSize(num_media_packets - num_fec_for_imp_packets); + + const uint8_t* packet_mask_sub_21 = + mask_table.fec_packet_mask_table()[num_media_packets - + num_fec_for_imp_packets - + 1][num_fec_remaining - 1]; + + ShiftFitSubMask(num_mask_bytes, res_mask_bytes, num_fec_for_imp_packets, + (num_fec_for_imp_packets + num_fec_remaining), + packet_mask_sub_21, packet_mask); + + } else if (mode == kModeOverlap || mode == kModeBiasFirstPacket) { + // sub_mask22 + + const uint8_t* packet_mask_sub_22 = + mask_table.fec_packet_mask_table()[num_media_packets - + 1][num_fec_remaining - 1]; + + FitSubMask(num_mask_bytes, num_mask_bytes, num_fec_remaining, + packet_mask_sub_22, + &packet_mask[num_fec_for_imp_packets * num_mask_bytes]); + + if (mode == kModeBiasFirstPacket) { + for (int i = 0; i < num_fec_remaining; ++i) { + int pkt_mask_idx = i * num_mask_bytes; + packet_mask[pkt_mask_idx] = packet_mask[pkt_mask_idx] | (1 << 7); + } + } + } else { + assert(false); + } +} + +// Protection for important (first partition) packets +void ImportantPacketProtection(int num_fec_for_imp_packets, + int num_imp_packets, + int num_mask_bytes, + uint8_t* packet_mask, + const PacketMaskTable& mask_table) { + const int num_imp_mask_bytes = PacketMaskSize(num_imp_packets); + + // Get sub_mask1 from table + const uint8_t* packet_mask_sub_1 = + mask_table.fec_packet_mask_table()[num_imp_packets - + 1][num_fec_for_imp_packets - 1]; + + FitSubMask(num_mask_bytes, num_imp_mask_bytes, num_fec_for_imp_packets, + packet_mask_sub_1, packet_mask); +} + +// This function sets the protection allocation: i.e., how many FEC packets +// to use for num_imp (1st partition) packets, given the: number of media +// packets, number of FEC packets, and number of 1st partition packets. +int SetProtectionAllocation(int num_media_packets, + int num_fec_packets, + int num_imp_packets) { + // TODO(marpan): test different cases for protection allocation: + + // Use at most (alloc_par * num_fec_packets) for important packets. + float alloc_par = 0.5; + int max_num_fec_for_imp = alloc_par * num_fec_packets; + + int num_fec_for_imp_packets = (num_imp_packets < max_num_fec_for_imp) + ? num_imp_packets + : max_num_fec_for_imp; + + // Fall back to equal protection in this case + if (num_fec_packets == 1 && (num_media_packets > 2 * num_imp_packets)) { + num_fec_for_imp_packets = 0; + } + + return num_fec_for_imp_packets; +} + +// Modification for UEP: reuse the off-line tables for the packet masks. +// Note: these masks were designed for equal packet protection case, +// assuming random packet loss. + +// Current version has 3 modes (options) to build UEP mask from existing ones. +// Various other combinations may be added in future versions. +// Longer-term, we may add another set of tables specifically for UEP cases. +// TODO(marpan): also consider modification of masks for bursty loss cases. + +// Mask is characterized as (#packets_to_protect, #fec_for_protection). +// Protection factor defined as: (#fec_for_protection / #packets_to_protect). + +// Let k=num_media_packets, n=total#packets, (n-k)=num_fec_packets, +// m=num_imp_packets. + +// For ProtectionMode 0 and 1: +// one mask (sub_mask1) is used for 1st partition packets, +// the other mask (sub_mask21/22, for 0/1) is for the remaining FEC packets. + +// In both mode 0 and 1, the packets of 1st partition (num_imp_packets) are +// treated equally important, and are afforded more protection than the +// residual partition packets. + +// For num_imp_packets: +// sub_mask1 = (m, t): protection = t/(m), where t=F(k,n-k,m). +// t=F(k,n-k,m) is the number of packets used to protect first partition in +// sub_mask1. This is determined from the function SetProtectionAllocation(). + +// For the left-over protection: +// Mode 0: sub_mask21 = (k-m,n-k-t): protection = (n-k-t)/(k-m) +// mode 0 has no protection overlap between the two partitions. +// For mode 0, we would typically set t = min(m, n-k). + +// Mode 1: sub_mask22 = (k, n-k-t), with protection (n-k-t)/(k) +// mode 1 has protection overlap between the two partitions (preferred). + +// For ProtectionMode 2: +// This gives 1st packet of list (which is 1st packet of 1st partition) more +// protection. In mode 2, the equal protection mask (which is obtained from +// mode 1 for t=0) is modified (more "1s" added in 1st column of packet mask) +// to bias higher protection for the 1st source packet. + +// Protection Mode 2 may be extended for a sort of sliding protection +// (i.e., vary the number/density of "1s" across columns) across packets. + +void UnequalProtectionMask(int num_media_packets, + int num_fec_packets, + int num_imp_packets, + int num_mask_bytes, + uint8_t* packet_mask, + const PacketMaskTable& mask_table) { + // Set Protection type and allocation + // TODO(marpan): test/update for best mode and some combinations thereof. + + ProtectionMode mode = kModeOverlap; + int num_fec_for_imp_packets = 0; + + if (mode != kModeBiasFirstPacket) { + num_fec_for_imp_packets = SetProtectionAllocation( + num_media_packets, num_fec_packets, num_imp_packets); + } + + int num_fec_remaining = num_fec_packets - num_fec_for_imp_packets; + // Done with setting protection type and allocation + + // + // Generate sub_mask1 + // + if (num_fec_for_imp_packets > 0) { + ImportantPacketProtection(num_fec_for_imp_packets, num_imp_packets, + num_mask_bytes, packet_mask, mask_table); + } + + // + // Generate sub_mask2 + // + if (num_fec_remaining > 0) { + RemainingPacketProtection(num_media_packets, num_fec_remaining, + num_fec_for_imp_packets, num_mask_bytes, mode, + packet_mask, mask_table); + } +} + +void GeneratePacketMasks(int num_media_packets, + int num_fec_packets, + int num_imp_packets, + bool use_unequal_protection, + const PacketMaskTable& mask_table, + uint8_t* packet_mask) { + assert(num_media_packets > 0); + assert(num_fec_packets <= num_media_packets && num_fec_packets > 0); + assert(num_imp_packets <= num_media_packets && num_imp_packets >= 0); + + const int num_mask_bytes = PacketMaskSize(num_media_packets); + + // Equal-protection for these cases. + if (!use_unequal_protection || num_imp_packets == 0) { + // Retrieve corresponding mask table directly:for equal-protection case. + // Mask = (k,n-k), with protection factor = (n-k)/k, + // where k = num_media_packets, n=total#packets, (n-k)=num_fec_packets. + memcpy(packet_mask, + mask_table.fec_packet_mask_table()[num_media_packets - + 1][num_fec_packets - 1], + num_fec_packets * num_mask_bytes); + } else { // UEP case + UnequalProtectionMask(num_media_packets, num_fec_packets, num_imp_packets, + num_mask_bytes, packet_mask, mask_table); + } // End of UEP modification +} // End of GetPacketMasks + +size_t PacketMaskSize(size_t num_sequence_numbers) { + RTC_DCHECK_LE(num_sequence_numbers, 8 * kUlpfecPacketMaskSizeLBitSet); + if (num_sequence_numbers > 8 * kUlpfecPacketMaskSizeLBitClear) { + return kUlpfecPacketMaskSizeLBitSet; + } + return kUlpfecPacketMaskSizeLBitClear; +} + +void InsertZeroColumns(int num_zeros, + uint8_t* new_mask, + int new_mask_bytes, + int num_fec_packets, + int new_bit_index) { + for (uint16_t row = 0; row < num_fec_packets; ++row) { + const int new_byte_index = row * new_mask_bytes + new_bit_index / 8; + const int max_shifts = (7 - (new_bit_index % 8)); + new_mask[new_byte_index] <<= std::min(num_zeros, max_shifts); + } +} + +void CopyColumn(uint8_t* new_mask, + int new_mask_bytes, + uint8_t* old_mask, + int old_mask_bytes, + int num_fec_packets, + int new_bit_index, + int old_bit_index) { + // Copy column from the old mask to the beginning of the new mask and shift it + // out from the old mask. + for (uint16_t row = 0; row < num_fec_packets; ++row) { + int new_byte_index = row * new_mask_bytes + new_bit_index / 8; + int old_byte_index = row * old_mask_bytes + old_bit_index / 8; + new_mask[new_byte_index] |= ((old_mask[old_byte_index] & 0x80) >> 7); + if (new_bit_index % 8 != 7) { + new_mask[new_byte_index] <<= 1; + } + old_mask[old_byte_index] <<= 1; + } +} + +} // namespace internal +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h new file mode 100644 index 0000000000..0c8f0a3e3c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h @@ -0,0 +1,108 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_ +#define MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_ + +#include "modules/include/module_common_types.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +// Maximum number of media packets that can be protected +// by these packet masks. +constexpr size_t kUlpfecMaxMediaPackets = 48; + +// Packet mask size in bytes (given L bit). +constexpr size_t kUlpfecPacketMaskSizeLBitClear = 2; +constexpr size_t kUlpfecPacketMaskSizeLBitSet = 6; + +// Convenience constants. +constexpr size_t kUlpfecMinPacketMaskSize = kUlpfecPacketMaskSizeLBitClear; +constexpr size_t kUlpfecMaxPacketMaskSize = kUlpfecPacketMaskSizeLBitSet; + +namespace internal { + +class PacketMaskTable { + public: + PacketMaskTable(FecMaskType fec_mask_type, int num_media_packets); + ~PacketMaskTable() {} + FecMaskType fec_mask_type() const { return fec_mask_type_; } + const uint8_t* const* const* fec_packet_mask_table() const { + return fec_packet_mask_table_; + } + + private: + FecMaskType InitMaskType(FecMaskType fec_mask_type, int num_media_packets); + const uint8_t* const* const* InitMaskTable(FecMaskType fec_mask_type_); + const FecMaskType fec_mask_type_; + const uint8_t* const* const* fec_packet_mask_table_; +}; + +// Returns an array of packet masks. The mask of a single FEC packet +// corresponds to a number of mask bytes. The mask indicates which +// media packets should be protected by the FEC packet. + +// \param[in] num_media_packets The number of media packets to protect. +// [1, max_media_packets]. +// \param[in] num_fec_packets The number of FEC packets which will +// be generated. [1, num_media_packets]. +// \param[in] num_imp_packets The number of important packets. +// [0, num_media_packets]. +// num_imp_packets = 0 is the equal +// protection scenario. +// \param[in] use_unequal_protection Enables unequal protection: allocates +// more protection to the num_imp_packets. +// \param[in] mask_table An instance of the |PacketMaskTable| +// class, which contains the type of FEC +// packet mask used, and a pointer to the +// corresponding packet masks. +// \param[out] packet_mask A pointer to hold the packet mask array, +// of size: num_fec_packets * +// "number of mask bytes". +void GeneratePacketMasks(int num_media_packets, int num_fec_packets, + int num_imp_packets, bool use_unequal_protection, + const PacketMaskTable& mask_table, + uint8_t* packet_mask); + +// Returns the required packet mask size, given the number of sequence numbers +// that will be covered. +size_t PacketMaskSize(size_t num_sequence_numbers); + +// Inserts |num_zeros| zero columns into |new_mask| at position +// |new_bit_index|. If the current byte of |new_mask| can't fit all zeros, the +// byte will be filled with zeros from |new_bit_index|, but the next byte will +// be untouched. +void InsertZeroColumns(int num_zeros, + uint8_t* new_mask, + int new_mask_bytes, + int num_fec_packets, + int new_bit_index); + +// Copies the left most bit column from the byte pointed to by +// |old_bit_index| in |old_mask| to the right most column of the byte pointed +// to by |new_bit_index| in |new_mask|. |old_mask_bytes| and |new_mask_bytes| +// represent the number of bytes used per row for each mask. |num_fec_packets| +// represent the number of rows of the masks. +// The copied bit is shifted out from |old_mask| and is shifted one step to +// the left in |new_mask|. |new_mask| will contain "xxxx xxn0" after this +// operation, where x are previously inserted bits and n is the new bit. +void CopyColumn(uint8_t* new_mask, + int new_mask_bytes, + uint8_t* old_mask, + int old_mask_bytes, + int num_fec_packets, + int new_bit_index, + int old_bit_index); + +} // namespace internal +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc new file mode 100644 index 0000000000..f3b0becd90 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc @@ -0,0 +1,290 @@ +/* +* 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 <algorithm> +#include <iterator> +#include <list> +#include <memory> +#include <set> + +#include "api/call/transport.h" +#include "call/rtp_stream_receiver_controller.h" +#include "call/rtx_receive_stream.h" +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "rtc_base/rate_limiter.h" +#include "test/gtest.h" + +namespace webrtc { + +const int kVideoNackListSize = 30; +const uint32_t kTestSsrc = 3456; +const uint32_t kTestRtxSsrc = kTestSsrc + 1; +const uint16_t kTestSequenceNumber = 2345; +const uint32_t kTestNumberOfPackets = 1350; +const int kTestNumberOfRtxPackets = 149; +const int kNumFrames = 30; +const int kPayloadType = 123; +const int kRtxPayloadType = 98; +const int64_t kMaxRttMs = 1000; + +class VerifyingMediaStream : public RtpPacketSinkInterface { + public: + VerifyingMediaStream() {} + + void OnRtpPacket(const RtpPacketReceived& packet) override { + if (!sequence_numbers_.empty()) + EXPECT_EQ(kTestSsrc, packet.Ssrc()); + + sequence_numbers_.push_back(packet.SequenceNumber()); + } + std::list<uint16_t> sequence_numbers_; +}; + +class RtxLoopBackTransport : public webrtc::Transport { + public: + explicit RtxLoopBackTransport(uint32_t rtx_ssrc) + : count_(0), + packet_loss_(0), + consecutive_drop_start_(0), + consecutive_drop_end_(0), + rtx_ssrc_(rtx_ssrc), + count_rtx_ssrc_(0), + module_(NULL) {} + + void SetSendModule(RtpRtcp* rtpRtcpModule) { + module_ = rtpRtcpModule; + } + + void DropEveryNthPacket(int n) { packet_loss_ = n; } + + void DropConsecutivePackets(int start, int total) { + consecutive_drop_start_ = start; + consecutive_drop_end_ = start + total; + packet_loss_ = 0; + } + + bool SendRtp(const uint8_t* data, + size_t len, + const PacketOptions& options) override { + count_++; + RtpPacketReceived packet; + if (!packet.Parse(data, len)) + return false; + if (packet.Ssrc() == rtx_ssrc_) { + count_rtx_ssrc_++; + } else { + // For non-RTX packets only. + expected_sequence_numbers_.insert(expected_sequence_numbers_.end(), + packet.SequenceNumber()); + } + if (packet_loss_ > 0) { + if ((count_ % packet_loss_) == 0) { + return true; + } + } else if (count_ >= consecutive_drop_start_ && + count_ < consecutive_drop_end_) { + return true; + } + EXPECT_TRUE(stream_receiver_controller_.OnRtpPacket(packet)); + return true; + } + + bool SendRtcp(const uint8_t* data, size_t len) override { + module_->IncomingRtcpPacket((const uint8_t*)data, len); + return true; + } + int count_; + int packet_loss_; + int consecutive_drop_start_; + int consecutive_drop_end_; + uint32_t rtx_ssrc_; + int count_rtx_ssrc_; + RtpRtcp* module_; + RtpStreamReceiverController stream_receiver_controller_; + std::set<uint16_t> expected_sequence_numbers_; +}; + +class RtpRtcpRtxNackTest : public ::testing::Test { + protected: + RtpRtcpRtxNackTest() + : rtp_rtcp_module_(nullptr), + transport_(kTestRtxSsrc), + rtx_stream_(&media_stream_, + rtx_associated_payload_types_, + kTestSsrc), + payload_data_length(sizeof(payload_data)), + fake_clock(123456), + retransmission_rate_limiter_(&fake_clock, kMaxRttMs) {} + ~RtpRtcpRtxNackTest() {} + + void SetUp() override { + RtpRtcp::Configuration configuration; + configuration.audio = false; + configuration.clock = &fake_clock; + receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock)); + configuration.receive_statistics = receive_statistics_.get(); + configuration.outgoing_transport = &transport_; + configuration.retransmission_rate_limiter = &retransmission_rate_limiter_; + rtp_rtcp_module_ = RtpRtcp::CreateRtpRtcp(configuration); + + rtp_rtcp_module_->SetSSRC(kTestSsrc); + rtp_rtcp_module_->SetRTCPStatus(RtcpMode::kCompound); + rtp_rtcp_module_->SetStorePacketsStatus(true, 600); + EXPECT_EQ(0, rtp_rtcp_module_->SetSendingStatus(true)); + rtp_rtcp_module_->SetSequenceNumber(kTestSequenceNumber); + rtp_rtcp_module_->SetStartTimestamp(111111); + + // Used for NACK processing. + // TODO(nisse): Unclear on which side? It's confusing to use a + // single rtp_rtcp module for both send and receive side. + rtp_rtcp_module_->SetRemoteSSRC(kTestSsrc); + + rtp_rtcp_module_->RegisterVideoSendPayload(kPayloadType, "video"); + rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType); + transport_.SetSendModule(rtp_rtcp_module_); + media_receiver_ = transport_.stream_receiver_controller_.CreateReceiver( + kTestSsrc, &media_stream_); + + for (size_t n = 0; n < payload_data_length; n++) { + payload_data[n] = n % 10; + } + } + + int BuildNackList(uint16_t* nack_list) { + media_stream_.sequence_numbers_.sort(); + std::list<uint16_t> missing_sequence_numbers; + std::list<uint16_t>::iterator it = media_stream_.sequence_numbers_.begin(); + + while (it != media_stream_.sequence_numbers_.end()) { + uint16_t sequence_number_1 = *it; + ++it; + if (it != media_stream_.sequence_numbers_.end()) { + uint16_t sequence_number_2 = *it; + // Add all missing sequence numbers to list + for (uint16_t i = sequence_number_1 + 1; i < sequence_number_2; ++i) { + missing_sequence_numbers.push_back(i); + } + } + } + int n = 0; + for (it = missing_sequence_numbers.begin(); + it != missing_sequence_numbers.end(); ++it) { + nack_list[n++] = (*it); + } + return n; + } + + bool ExpectedPacketsReceived() { + std::list<uint16_t> received_sorted; + std::copy(media_stream_.sequence_numbers_.begin(), + media_stream_.sequence_numbers_.end(), + std::back_inserter(received_sorted)); + received_sorted.sort(); + return received_sorted.size() == + transport_.expected_sequence_numbers_.size() && + std::equal(received_sorted.begin(), received_sorted.end(), + transport_.expected_sequence_numbers_.begin()); + } + + void RunRtxTest(RtxMode rtx_method, int loss) { + rtx_receiver_ = transport_.stream_receiver_controller_.CreateReceiver( + kTestRtxSsrc, &rtx_stream_); + rtp_rtcp_module_->SetRtxSendStatus(rtx_method); + rtp_rtcp_module_->SetRtxSsrc(kTestRtxSsrc); + transport_.DropEveryNthPacket(loss); + uint32_t timestamp = 3000; + uint16_t nack_list[kVideoNackListSize]; + for (int frame = 0; frame < kNumFrames; ++frame) { + EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData( + webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90, + payload_data, payload_data_length, nullptr, nullptr, nullptr)); + // Min required delay until retransmit = 5 + RTT ms (RTT = 0). + fake_clock.AdvanceTimeMilliseconds(5); + int length = BuildNackList(nack_list); + if (length > 0) + rtp_rtcp_module_->SendNACK(nack_list, length); + fake_clock.AdvanceTimeMilliseconds(28); // 33ms - 5ms delay. + rtp_rtcp_module_->Process(); + // Prepare next frame. + timestamp += 3000; + } + media_stream_.sequence_numbers_.sort(); + } + + void TearDown() override { delete rtp_rtcp_module_; } + + std::unique_ptr<ReceiveStatistics> receive_statistics_; + RtpRtcp* rtp_rtcp_module_; + RtxLoopBackTransport transport_; + const std::map<int, int> rtx_associated_payload_types_ = + {{kRtxPayloadType, kPayloadType}}; + VerifyingMediaStream media_stream_; + RtxReceiveStream rtx_stream_; + uint8_t payload_data[65000]; + size_t payload_data_length; + SimulatedClock fake_clock; + RateLimiter retransmission_rate_limiter_; + std::unique_ptr<RtpStreamReceiverInterface> media_receiver_; + std::unique_ptr<RtpStreamReceiverInterface> rtx_receiver_; +}; + +TEST_F(RtpRtcpRtxNackTest, LongNackList) { + const int kNumPacketsToDrop = 900; + const int kNumRequiredRtcp = 4; + uint32_t timestamp = 3000; + uint16_t nack_list[kNumPacketsToDrop]; + // Disable StorePackets to be able to set a larger packet history. + rtp_rtcp_module_->SetStorePacketsStatus(false, 0); + // Enable StorePackets with a packet history of 2000 packets. + rtp_rtcp_module_->SetStorePacketsStatus(true, 2000); + // Drop 900 packets from the second one so that we get a NACK list which is + // big enough to require 4 RTCP packets to be fully transmitted to the sender. + transport_.DropConsecutivePackets(2, kNumPacketsToDrop); + // Send 30 frames which at the default size is roughly what we need to get + // enough packets. + for (int frame = 0; frame < kNumFrames; ++frame) { + EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData( + webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90, + payload_data, payload_data_length, nullptr, nullptr, nullptr)); + // Prepare next frame. + timestamp += 3000; + fake_clock.AdvanceTimeMilliseconds(33); + rtp_rtcp_module_->Process(); + } + EXPECT_FALSE(transport_.expected_sequence_numbers_.empty()); + EXPECT_FALSE(media_stream_.sequence_numbers_.empty()); + size_t last_receive_count = media_stream_.sequence_numbers_.size(); + int length = BuildNackList(nack_list); + for (int i = 0; i < kNumRequiredRtcp - 1; ++i) { + rtp_rtcp_module_->SendNACK(nack_list, length); + EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count); + last_receive_count = media_stream_.sequence_numbers_.size(); + EXPECT_FALSE(ExpectedPacketsReceived()); + } + rtp_rtcp_module_->SendNACK(nack_list, length); + EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count); + EXPECT_TRUE(ExpectedPacketsReceived()); +} + +TEST_F(RtpRtcpRtxNackTest, RtxNack) { + RunRtxTest(kRtxRetransmitted, 10); + EXPECT_EQ(kTestSequenceNumber, *(media_stream_.sequence_numbers_.begin())); + EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1, + *(media_stream_.sequence_numbers_.rbegin())); + EXPECT_EQ(kTestNumberOfPackets, media_stream_.sequence_numbers_.size()); + EXPECT_EQ(kTestNumberOfRtxPackets, transport_.count_rtx_ssrc_); + EXPECT_TRUE(ExpectedPacketsReceived()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc new file mode 100644 index 0000000000..69c20c4cf8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/packet_loss_stats.h" + +#include <vector> + +#include "rtc_base/checks.h" + +// After this many packets are added, adding additional packets will cause the +// oldest packets to be pruned from the buffer. +static const int kBufferSize = 100; + +namespace webrtc { + +PacketLossStats::PacketLossStats() + : single_loss_historic_count_(0), + multiple_loss_historic_event_count_(0), + multiple_loss_historic_packet_count_(0) { +} + +void PacketLossStats::AddLostPacket(uint16_t sequence_number) { + // Detect sequence number wrap around. + if (!lost_packets_buffer_.empty() && + static_cast<int>(*(lost_packets_buffer_.rbegin())) - sequence_number + > 0x8000) { + // The buffer contains large numbers and this is a small number. + lost_packets_wrapped_buffer_.insert(sequence_number); + } else { + lost_packets_buffer_.insert(sequence_number); + } + if (lost_packets_wrapped_buffer_.size() + lost_packets_buffer_.size() + > kBufferSize || (!lost_packets_wrapped_buffer_.empty() && + *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000)) { + PruneBuffer(); + } +} + +int PacketLossStats::GetSingleLossCount() const { + int single_loss_count, unused1, unused2; + ComputeLossCounts(&single_loss_count, &unused1, &unused2); + return single_loss_count; +} + +int PacketLossStats::GetMultipleLossEventCount() const { + int event_count, unused1, unused2; + ComputeLossCounts(&unused1, &event_count, &unused2); + return event_count; +} + +int PacketLossStats::GetMultipleLossPacketCount() const { + int packet_count, unused1, unused2; + ComputeLossCounts(&unused1, &unused2, &packet_count); + return packet_count; +} + +void PacketLossStats::ComputeLossCounts( + int* out_single_loss_count, + int* out_multiple_loss_event_count, + int* out_multiple_loss_packet_count) const { + *out_single_loss_count = single_loss_historic_count_; + *out_multiple_loss_event_count = multiple_loss_historic_event_count_; + *out_multiple_loss_packet_count = multiple_loss_historic_packet_count_; + if (lost_packets_buffer_.empty()) { + RTC_DCHECK(lost_packets_wrapped_buffer_.empty()); + return; + } + uint16_t last_num = 0; + int sequential_count = 0; + std::vector<const std::set<uint16_t>*> buffers; + buffers.push_back(&lost_packets_buffer_); + buffers.push_back(&lost_packets_wrapped_buffer_); + for (auto buffer : buffers) { + for (auto it = buffer->begin(); it != buffer->end(); ++it) { + uint16_t current_num = *it; + if (sequential_count > 0 && current_num != ((last_num + 1) & 0xFFFF)) { + if (sequential_count == 1) { + (*out_single_loss_count)++; + } else { + (*out_multiple_loss_event_count)++; + *out_multiple_loss_packet_count += sequential_count; + } + sequential_count = 0; + } + sequential_count++; + last_num = current_num; + } + } + if (sequential_count == 1) { + (*out_single_loss_count)++; + } else if (sequential_count > 1) { + (*out_multiple_loss_event_count)++; + *out_multiple_loss_packet_count += sequential_count; + } +} + +void PacketLossStats::PruneBuffer() { + // Remove the oldest lost packet and any contiguous packets and move them + // into the historic counts. + auto it = lost_packets_buffer_.begin(); + uint16_t last_removed = 0; + int remove_count = 0; + // Count adjacent packets and continue counting if it is wrap around by + // swapping in the wrapped buffer and letting our value wrap as well. + while (remove_count == 0 || (!lost_packets_buffer_.empty() && + *it == ((last_removed + 1) & 0xFFFF))) { + last_removed = *it; + remove_count++; + auto to_erase = it++; + lost_packets_buffer_.erase(to_erase); + if (lost_packets_buffer_.empty()) { + lost_packets_buffer_.swap(lost_packets_wrapped_buffer_); + it = lost_packets_buffer_.begin(); + } + } + if (remove_count > 1) { + multiple_loss_historic_event_count_++; + multiple_loss_historic_packet_count_ += remove_count; + } else { + single_loss_historic_count_++; + } + // Continue pruning if the wrapped buffer is beyond a threshold and there are + // things left in the pre-wrapped buffer. + if (!lost_packets_wrapped_buffer_.empty() && + *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000) { + PruneBuffer(); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.h new file mode 100644 index 0000000000..683399f123 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.h @@ -0,0 +1,57 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_ +#define MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_ + +#include <stdint.h> +#include <set> + +namespace webrtc { + +// Keeps track of statistics of packet loss including whether losses are a +// single packet or multiple packets in a row. +class PacketLossStats { + public: + PacketLossStats(); + ~PacketLossStats() {} + + // Adds a lost packet to the stats by sequence number. + void AddLostPacket(uint16_t sequence_number); + + // Queries the number of packets that were lost by themselves, no neighboring + // packets were lost. + int GetSingleLossCount() const; + + // Queries the number of times that multiple packets with sequential numbers + // were lost. This is the number of events with more than one packet lost, + // regardless of the size of the event; + int GetMultipleLossEventCount() const; + + // Queries the number of packets lost in multiple packet loss events. Combined + // with the event count, this can be used to determine the average event size. + int GetMultipleLossPacketCount() const; + + private: + std::set<uint16_t> lost_packets_buffer_; + std::set<uint16_t> lost_packets_wrapped_buffer_; + int single_loss_historic_count_; + int multiple_loss_historic_event_count_; + int multiple_loss_historic_packet_count_; + + void ComputeLossCounts(int* out_single_loss_count, + int* out_multiple_loss_event_count, + int* out_multiple_loss_packet_count) const; + void PruneBuffer(); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc new file mode 100644 index 0000000000..3731250718 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc @@ -0,0 +1,197 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/packet_loss_stats.h" +#include "test/gtest.h" + +namespace webrtc { + +class PacketLossStatsTest : public ::testing::Test { + protected: + PacketLossStats stats_; +}; + +// Add a lost packet as every other packet, they should all count as single +// losses. +TEST_F(PacketLossStatsTest, EveryOtherPacket) { + for (int i = 0; i < 1000; i += 2) { + stats_.AddLostPacket(i); + } + EXPECT_EQ(500, stats_.GetSingleLossCount()); + EXPECT_EQ(0, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(0, stats_.GetMultipleLossPacketCount()); +} + +// Add a lost packet as every other packet, but such that the sequence numbers +// will wrap around while they are being added. +TEST_F(PacketLossStatsTest, EveryOtherPacketWrapped) { + for (int i = 65500; i < 66500; i += 2) { + stats_.AddLostPacket(i & 0xFFFF); + } + EXPECT_EQ(500, stats_.GetSingleLossCount()); + EXPECT_EQ(0, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(0, stats_.GetMultipleLossPacketCount()); +} + +// Add a lost packet as every other packet, but such that the sequence numbers +// will wrap around close to the very end, such that the buffer contains packets +// on either side of the wrapping. +TEST_F(PacketLossStatsTest, EveryOtherPacketWrappedAtEnd) { + for (int i = 64600; i < 65600; i += 2) { + stats_.AddLostPacket(i & 0xFFFF); + } + EXPECT_EQ(500, stats_.GetSingleLossCount()); + EXPECT_EQ(0, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(0, stats_.GetMultipleLossPacketCount()); +} + +// Add a lost packet as the first three of every eight packets. Each set of +// three should count as a multiple loss event and three multiple loss packets. +TEST_F(PacketLossStatsTest, FirstThreeOfEight) { + for (int i = 0; i < 1000; ++i) { + if ((i & 7) < 3) { + stats_.AddLostPacket(i); + } + } + EXPECT_EQ(0, stats_.GetSingleLossCount()); + EXPECT_EQ(125, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(375, stats_.GetMultipleLossPacketCount()); +} + +// Add a lost packet as the first three of every eight packets such that the +// sequence numbers wrap in the middle of adding them. +TEST_F(PacketLossStatsTest, FirstThreeOfEightWrapped) { + for (int i = 65500; i < 66500; ++i) { + if ((i & 7) < 3) { + stats_.AddLostPacket(i & 0xFFFF); + } + } + EXPECT_EQ(0, stats_.GetSingleLossCount()); + EXPECT_EQ(125, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(375, stats_.GetMultipleLossPacketCount()); +} + +// Add a lost packet as the first three of every eight packets such that the +// sequence numbers wrap near the end of adding them and there are still numbers +// in the buffer from before the wrapping. +TEST_F(PacketLossStatsTest, FirstThreeOfEightWrappedAtEnd) { + for (int i = 64600; i < 65600; ++i) { + if ((i & 7) < 3) { + stats_.AddLostPacket(i & 0xFFFF); + } + } + EXPECT_EQ(0, stats_.GetSingleLossCount()); + EXPECT_EQ(125, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(375, stats_.GetMultipleLossPacketCount()); +} + +// Add loss packets as the first three and the fifth of every eight packets. The +// set of three should be multiple loss and the fifth should be single loss. +TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEight) { + for (int i = 0; i < 1000; ++i) { + if ((i & 7) < 3 || (i & 7) == 4) { + stats_.AddLostPacket(i); + } + } + EXPECT_EQ(125, stats_.GetSingleLossCount()); + EXPECT_EQ(125, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(375, stats_.GetMultipleLossPacketCount()); +} + +// Add loss packets as the first three and the fifth of every eight packets such +// that the sequence numbers wrap in the middle of adding them. +TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEightWrapped) { + for (int i = 65500; i < 66500; ++i) { + if ((i & 7) < 3 || (i & 7) == 4) { + stats_.AddLostPacket(i & 0xFFFF); + } + } + EXPECT_EQ(125, stats_.GetSingleLossCount()); + EXPECT_EQ(125, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(375, stats_.GetMultipleLossPacketCount()); +} + +// Add loss packets as the first three and the fifth of every eight packets such +// that the sequence numbers wrap near the end of adding them and there are +// packets from before the wrapping still in the buffer. +TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEightWrappedAtEnd) { + for (int i = 64600; i < 65600; ++i) { + if ((i & 7) < 3 || (i & 7) == 4) { + stats_.AddLostPacket(i & 0xFFFF); + } + } + EXPECT_EQ(125, stats_.GetSingleLossCount()); + EXPECT_EQ(125, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(375, stats_.GetMultipleLossPacketCount()); +} + +// Add loss packets such that there is a multiple loss event that continues +// around the wrapping of sequence numbers. +TEST_F(PacketLossStatsTest, MultipleLossEventWrapped) { + for (int i = 60000; i < 60500; i += 2) { + stats_.AddLostPacket(i); + } + for (int i = 65530; i < 65540; ++i) { + stats_.AddLostPacket(i & 0xFFFF); + } + EXPECT_EQ(250, stats_.GetSingleLossCount()); + EXPECT_EQ(1, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(10, stats_.GetMultipleLossPacketCount()); +} + +// Add loss packets such that there is a multiple loss event that continues +// around the wrapping of sequence numbers and then is pushed out of the buffer. +TEST_F(PacketLossStatsTest, MultipleLossEventWrappedPushedOut) { + for (int i = 60000; i < 60500; i += 2) { + stats_.AddLostPacket(i); + } + for (int i = 65530; i < 65540; ++i) { + stats_.AddLostPacket(i & 0xFFFF); + } + for (int i = 1000; i < 1500; i += 2) { + stats_.AddLostPacket(i); + } + EXPECT_EQ(500, stats_.GetSingleLossCount()); + EXPECT_EQ(1, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(10, stats_.GetMultipleLossPacketCount()); +} + +// Add loss packets out of order and ensure that they still get counted +// correctly as single or multiple loss events. +TEST_F(PacketLossStatsTest, OutOfOrder) { + for (int i = 0; i < 1000; i += 10) { + stats_.AddLostPacket(i + 5); + stats_.AddLostPacket(i + 7); + stats_.AddLostPacket(i + 4); + stats_.AddLostPacket(i + 1); + stats_.AddLostPacket(i + 2); + } + EXPECT_EQ(100, stats_.GetSingleLossCount()); + EXPECT_EQ(200, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(400, stats_.GetMultipleLossPacketCount()); +} + +// Add loss packets out of order and ensure that they still get counted +// correctly as single or multiple loss events, and wrap in the middle of +// adding. +TEST_F(PacketLossStatsTest, OutOfOrderWrapped) { + for (int i = 65000; i < 66000; i += 10) { + stats_.AddLostPacket((i + 5) & 0xFFFF); + stats_.AddLostPacket((i + 7) & 0xFFFF); + stats_.AddLostPacket((i + 4) & 0xFFFF); + stats_.AddLostPacket((i + 1) & 0xFFFF); + stats_.AddLostPacket((i + 2) & 0xFFFF); + } + EXPECT_EQ(100, stats_.GetSingleLossCount()); + EXPECT_EQ(200, stats_.GetMultipleLossEventCount()); + EXPECT_EQ(400, stats_.GetMultipleLossPacketCount()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.cc new file mode 100644 index 0000000000..d3a75dd13a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/playout_delay_oracle.h" + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +PlayoutDelayOracle::PlayoutDelayOracle() + : high_sequence_number_(0), + send_playout_delay_(false), + ssrc_(0), + playout_delay_{-1, -1} {} + +PlayoutDelayOracle::~PlayoutDelayOracle() {} + +void PlayoutDelayOracle::UpdateRequest(uint32_t ssrc, + PlayoutDelay playout_delay, + uint16_t seq_num) { + rtc::CritScope lock(&crit_sect_); + RTC_DCHECK_LE(playout_delay.min_ms, PlayoutDelayLimits::kMaxMs); + RTC_DCHECK_LE(playout_delay.max_ms, PlayoutDelayLimits::kMaxMs); + RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms); + int64_t unwrapped_seq_num = unwrapper_.Unwrap(seq_num); + if (playout_delay.min_ms >= 0 && + playout_delay.min_ms != playout_delay_.min_ms) { + send_playout_delay_ = true; + playout_delay_.min_ms = playout_delay.min_ms; + high_sequence_number_ = unwrapped_seq_num; + } + + if (playout_delay.max_ms >= 0 && + playout_delay.max_ms != playout_delay_.max_ms) { + send_playout_delay_ = true; + playout_delay_.max_ms = playout_delay.max_ms; + high_sequence_number_ = unwrapped_seq_num; + } + ssrc_ = ssrc; +} + +// If an ACK is received on the packet containing the playout delay extension, +// we stop sending the extension on future packets. +void PlayoutDelayOracle::OnReceivedRtcpReportBlocks( + const ReportBlockList& report_blocks) { + rtc::CritScope lock(&crit_sect_); + for (const RTCPReportBlock& report_block : report_blocks) { + if ((ssrc_ == report_block.source_ssrc) && send_playout_delay_ && + (report_block.extended_highest_sequence_number > + high_sequence_number_)) { + send_playout_delay_ = false; + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h new file mode 100644 index 0000000000..6e6e253c8c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_PLAYOUT_DELAY_ORACLE_H_ +#define MODULES_RTP_RTCP_SOURCE_PLAYOUT_DELAY_ORACLE_H_ + +#include <stdint.h> + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +// This class tracks the application requests to limit minimum and maximum +// playout delay and makes a decision on whether the current RTP frame +// should include the playout out delay extension header. +// +// Playout delay can be defined in terms of capture and render time as follows: +// +// Render time = Capture time in receiver time + playout delay +// +// The application specifies a minimum and maximum limit for the playout delay +// which are both communicated to the receiver and the receiver can adapt +// the playout delay within this range based on observed network jitter. +class PlayoutDelayOracle { + public: + PlayoutDelayOracle(); + ~PlayoutDelayOracle(); + + // Returns true if the current frame should include the playout delay + // extension + bool send_playout_delay() const { + rtc::CritScope lock(&crit_sect_); + return send_playout_delay_; + } + + // Returns current playout delay. + PlayoutDelay playout_delay() const { + rtc::CritScope lock(&crit_sect_); + return playout_delay_; + } + + // Updates the application requested playout delay, current ssrc + // and the current sequence number. + void UpdateRequest(uint32_t ssrc, + PlayoutDelay playout_delay, + uint16_t seq_num); + + void OnReceivedRtcpReportBlocks(const ReportBlockList& report_blocks); + + private: + // The playout delay information is updated from the encoder thread(s). + // The sequence number feedback is updated from the worker thread. + // Guards access to data across multiple threads. + rtc::CriticalSection crit_sect_; + // The current highest sequence number on which playout delay has been sent. + int64_t high_sequence_number_ RTC_GUARDED_BY(crit_sect_); + // Indicates whether the playout delay should go on the next frame. + bool send_playout_delay_ RTC_GUARDED_BY(crit_sect_); + // Sender ssrc. + uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_); + // Sequence number unwrapper. + SequenceNumberUnwrapper unwrapper_ RTC_GUARDED_BY(crit_sect_); + // Playout delay values on the next frame if |send_playout_delay_| is set. + PlayoutDelay playout_delay_ RTC_GUARDED_BY(crit_sect_); + + RTC_DISALLOW_COPY_AND_ASSIGN(PlayoutDelayOracle); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_PLAYOUT_DELAY_ORACLE_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc new file mode 100644 index 0000000000..099339d6d4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/playout_delay_oracle.h" + +#include "rtc_base/logging.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { +constexpr int kSsrc = 100; +constexpr int kSequenceNumber = 100; +constexpr int kMinPlayoutDelay = 0; +constexpr int kMaxPlayoutDelay = 150; +} // namespace + +class PlayoutDelayOracleTest : public ::testing::Test { + protected: + void ReportRTCPFeedback(int ssrc, int seq_num) { + RTCPReportBlock report_block; + report_block.source_ssrc = ssrc; + report_block.extended_highest_sequence_number = seq_num; + report_blocks_.push_back(report_block); + playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks_); + } + + ReportBlockList report_blocks_; + PlayoutDelayOracle playout_delay_oracle_; +}; + +TEST_F(PlayoutDelayOracleTest, DisabledByDefault) { + EXPECT_FALSE(playout_delay_oracle_.send_playout_delay()); + EXPECT_EQ(-1, playout_delay_oracle_.playout_delay().min_ms); + EXPECT_EQ(-1, playout_delay_oracle_.playout_delay().max_ms); +} + +TEST_F(PlayoutDelayOracleTest, SendPlayoutDelayUntilSeqNumberExceeds) { + PlayoutDelay playout_delay = {kMinPlayoutDelay, kMaxPlayoutDelay}; + playout_delay_oracle_.UpdateRequest(kSsrc, playout_delay, kSequenceNumber); + EXPECT_TRUE(playout_delay_oracle_.send_playout_delay()); + EXPECT_EQ(kMinPlayoutDelay, playout_delay_oracle_.playout_delay().min_ms); + EXPECT_EQ(kMaxPlayoutDelay, playout_delay_oracle_.playout_delay().max_ms); + + // Oracle indicates playout delay should be sent if highest sequence number + // acked is lower than the sequence number of the first packet containing + // playout delay. + ReportRTCPFeedback(kSsrc, kSequenceNumber - 1); + EXPECT_TRUE(playout_delay_oracle_.send_playout_delay()); + + // An invalid ssrc feedback report is dropped by the oracle. + ReportRTCPFeedback(kSsrc + 1, kSequenceNumber + 1); + EXPECT_TRUE(playout_delay_oracle_.send_playout_delay()); + + // Oracle indicates playout delay should not be sent if sequence number + // acked on a matching ssrc indicates the receiver has received the playout + // delay values. + ReportRTCPFeedback(kSsrc, kSequenceNumber + 1); + EXPECT_FALSE(playout_delay_oracle_.send_playout_delay()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc new file mode 100644 index 0000000000..4f956a93e9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc @@ -0,0 +1,496 @@ +/* + * 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 "modules/rtp_rtcp/source/receive_statistics_impl.h" + +#include <math.h> + +#include <cstdlib> +#include <vector> + +#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "modules/rtp_rtcp/source/time_util.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +const int64_t kStatisticsTimeoutMs = 8000; +const int64_t kStatisticsProcessIntervalMs = 1000; + +StreamStatistician::~StreamStatistician() {} + +StreamStatisticianImpl::StreamStatisticianImpl( + uint32_t ssrc, + Clock* clock, + RtcpStatisticsCallback* rtcp_callback, + StreamDataCountersCallback* rtp_callback) + : ssrc_(ssrc), + clock_(clock), + incoming_bitrate_(kStatisticsProcessIntervalMs, + RateStatistics::kBpsScale), + max_reordering_threshold_(kDefaultMaxReorderingThreshold), + jitter_q4_(0), + cumulative_loss_(0), + last_receive_time_ms_(0), + last_received_timestamp_(0), + received_seq_first_(0), + received_seq_max_(0), + received_seq_wraps_(0), + received_packet_overhead_(12), + last_report_inorder_packets_(0), + last_report_old_packets_(0), + last_report_seq_max_(0), + rtcp_callback_(rtcp_callback), + rtp_callback_(rtp_callback) {} + +void StreamStatisticianImpl::IncomingPacket(const RTPHeader& header, + size_t packet_length, + bool retransmitted) { + auto counters = UpdateCounters(header, packet_length, retransmitted); + rtp_callback_->DataCountersUpdated(counters, ssrc_); +} + +StreamDataCounters StreamStatisticianImpl::UpdateCounters( + const RTPHeader& header, + size_t packet_length, + bool retransmitted) { + rtc::CritScope cs(&stream_lock_); + bool in_order = InOrderPacketInternal(header.sequenceNumber); + RTC_DCHECK_EQ(ssrc_, header.ssrc); + incoming_bitrate_.Update(packet_length, clock_->TimeInMilliseconds()); + receive_counters_.transmitted.AddPacket(packet_length, header); + if (!in_order && retransmitted) { + receive_counters_.retransmitted.AddPacket(packet_length, header); + } + + if (receive_counters_.transmitted.packets == 1) { + received_seq_first_ = header.sequenceNumber; + receive_counters_.first_packet_time_ms = clock_->TimeInMilliseconds(); + } + + // Count only the new packets received. That is, if packets 1, 2, 3, 5, 4, 6 + // are received, 4 will be ignored. + if (in_order) { + // Current time in samples. + NtpTime receive_time = clock_->CurrentNtpTime(); + + // Wrong if we use RetransmitOfOldPacket. + if (receive_counters_.transmitted.packets > 1 && + received_seq_max_ > header.sequenceNumber) { + // Wrap around detected. + received_seq_wraps_++; + } + // New max. + received_seq_max_ = header.sequenceNumber; + + // If new time stamp and more than one in-order packet received, calculate + // new jitter statistics. + if (header.timestamp != last_received_timestamp_ && + (receive_counters_.transmitted.packets - + receive_counters_.retransmitted.packets) > 1) { + UpdateJitter(header, receive_time); + } + last_received_timestamp_ = header.timestamp; + last_receive_time_ntp_ = receive_time; + last_receive_time_ms_ = clock_->TimeInMilliseconds(); + } + + size_t packet_oh = header.headerLength + header.paddingLength; + + // Our measured overhead. Filter from RFC 5104 4.2.1.2: + // avg_OH (new) = 15/16*avg_OH (old) + 1/16*pckt_OH, + received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4; + return receive_counters_; +} + +void StreamStatisticianImpl::UpdateJitter(const RTPHeader& header, + NtpTime receive_time) { + uint32_t receive_time_rtp = + NtpToRtp(receive_time, header.payload_type_frequency); + uint32_t last_receive_time_rtp = + NtpToRtp(last_receive_time_ntp_, header.payload_type_frequency); + int32_t time_diff_samples = (receive_time_rtp - last_receive_time_rtp) - + (header.timestamp - last_received_timestamp_); + + time_diff_samples = std::abs(time_diff_samples); + + // lib_jingle sometimes deliver crazy jumps in TS for the same stream. + // If this happens, don't update jitter value. Use 5 secs video frequency + // as the threshold. + if (time_diff_samples < 450000) { + // Note we calculate in Q4 to avoid using float. + int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_; + jitter_q4_ += ((jitter_diff_q4 + 8) >> 4); + } +} + +void StreamStatisticianImpl::FecPacketReceived(const RTPHeader& header, + size_t packet_length) { + StreamDataCounters counters; + { + rtc::CritScope cs(&stream_lock_); + receive_counters_.fec.AddPacket(packet_length, header); + counters = receive_counters_; + } + rtp_callback_->DataCountersUpdated(counters, ssrc_); +} + +void StreamStatisticianImpl::SetMaxReorderingThreshold( + int max_reordering_threshold) { + rtc::CritScope cs(&stream_lock_); + max_reordering_threshold_ = max_reordering_threshold; +} + +bool StreamStatisticianImpl::GetStatistics(RtcpStatistics* statistics, + bool reset) { + { + rtc::CritScope cs(&stream_lock_); + if (received_seq_first_ == 0 && + receive_counters_.transmitted.payload_bytes == 0) { + // We have not received anything. + return false; + } + + if (!reset) { + if (last_report_inorder_packets_ == 0) { + // No report. + return false; + } + // Just get last report. + *statistics = last_reported_statistics_; + return true; + } + + *statistics = CalculateRtcpStatistics(); + } + + rtcp_callback_->StatisticsUpdated(*statistics, ssrc_); + return true; +} + +bool StreamStatisticianImpl::GetActiveStatisticsAndReset( + RtcpStatistics* statistics) { + { + rtc::CritScope cs(&stream_lock_); + if (clock_->CurrentNtpInMilliseconds() - last_receive_time_ntp_.ToMs() >= + kStatisticsTimeoutMs) { + // Not active. + return false; + } + if (received_seq_first_ == 0 && + receive_counters_.transmitted.payload_bytes == 0) { + // We have not received anything. + return false; + } + + *statistics = CalculateRtcpStatistics(); + } + + rtcp_callback_->StatisticsUpdated(*statistics, ssrc_); + return true; +} + +RtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics() { + RtcpStatistics stats; + + if (last_report_inorder_packets_ == 0) { + // First time we send a report. + last_report_seq_max_ = received_seq_first_ - 1; + } + + // Calculate fraction lost. + uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_); + + if (last_report_seq_max_ > received_seq_max_) { + // Can we assume that the seq_num can't go decrease over a full RTCP period? + exp_since_last = 0; + } + + // Number of received RTP packets since last report, counts all packets but + // not re-transmissions. + uint32_t rec_since_last = + (receive_counters_.transmitted.packets - + receive_counters_.retransmitted.packets) - last_report_inorder_packets_; + + // With NACK we don't know the expected retransmissions during the last + // second. We know how many "old" packets we have received. We just count + // the number of old received to estimate the loss, but it still does not + // guarantee an exact number since we run this based on time triggered by + // sending of an RTP packet. This should have a minimum effect. + + // With NACK we don't count old packets as received since they are + // re-transmitted. We use RTT to decide if a packet is re-ordered or + // re-transmitted. + uint32_t retransmitted_packets = + receive_counters_.retransmitted.packets - last_report_old_packets_; + rec_since_last += retransmitted_packets; + + int32_t missing = 0; + if (exp_since_last > rec_since_last) { + missing = (exp_since_last - rec_since_last); + } + uint8_t local_fraction_lost = 0; + if (exp_since_last) { + // Scale 0 to 255, where 255 is 100% loss. + local_fraction_lost = + static_cast<uint8_t>(255 * missing / exp_since_last); + } + stats.fraction_lost = local_fraction_lost; + + // We need a counter for cumulative loss too. + // TODO(danilchap): Ensure cumulative loss is below maximum value of 2^24. + cumulative_loss_ += missing; + stats.packets_lost = cumulative_loss_; + stats.extended_highest_sequence_number = + (received_seq_wraps_ << 16) + received_seq_max_; + // Note: internal jitter value is in Q4 and needs to be scaled by 1/16. + stats.jitter = jitter_q4_ >> 4; + + // Store this report. + last_reported_statistics_ = stats; + + // Only for report blocks in RTCP SR and RR. + last_report_inorder_packets_ = + receive_counters_.transmitted.packets - + receive_counters_.retransmitted.packets; + last_report_old_packets_ = receive_counters_.retransmitted.packets; + last_report_seq_max_ = received_seq_max_; + BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "cumulative_loss_pkts", + clock_->TimeInMilliseconds(), + cumulative_loss_, ssrc_); + BWE_TEST_LOGGING_PLOT_WITH_SSRC( + 1, "received_seq_max_pkts", clock_->TimeInMilliseconds(), + (received_seq_max_ - received_seq_first_), ssrc_); + + return stats; +} + +void StreamStatisticianImpl::GetDataCounters( + size_t* bytes_received, uint32_t* packets_received) const { + rtc::CritScope cs(&stream_lock_); + if (bytes_received) { + *bytes_received = receive_counters_.transmitted.payload_bytes + + receive_counters_.transmitted.header_bytes + + receive_counters_.transmitted.padding_bytes; + } + if (packets_received) { + *packets_received = receive_counters_.transmitted.packets; + } +} + +void StreamStatisticianImpl::GetReceiveStreamDataCounters( + StreamDataCounters* data_counters) const { + rtc::CritScope cs(&stream_lock_); + *data_counters = receive_counters_; +} + +uint32_t StreamStatisticianImpl::BitrateReceived() const { + rtc::CritScope cs(&stream_lock_); + return incoming_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0); +} + +bool StreamStatisticianImpl::IsRetransmitOfOldPacket( + const RTPHeader& header, int64_t min_rtt) const { + rtc::CritScope cs(&stream_lock_); + if (InOrderPacketInternal(header.sequenceNumber)) { + return false; + } + uint32_t frequency_khz = header.payload_type_frequency / 1000; + assert(frequency_khz > 0); + + int64_t time_diff_ms = clock_->TimeInMilliseconds() - + last_receive_time_ms_; + + // Diff in time stamp since last received in order. + uint32_t timestamp_diff = header.timestamp - last_received_timestamp_; + uint32_t rtp_time_stamp_diff_ms = timestamp_diff / frequency_khz; + + int64_t max_delay_ms = 0; + if (min_rtt == 0) { + // Jitter standard deviation in samples. + float jitter_std = sqrt(static_cast<float>(jitter_q4_ >> 4)); + + // 2 times the standard deviation => 95% confidence. + // And transform to milliseconds by dividing by the frequency in kHz. + max_delay_ms = static_cast<int64_t>((2 * jitter_std) / frequency_khz); + + // Min max_delay_ms is 1. + if (max_delay_ms == 0) { + max_delay_ms = 1; + } + } else { + max_delay_ms = (min_rtt / 3) + 1; + } + return time_diff_ms > rtp_time_stamp_diff_ms + max_delay_ms; +} + +bool StreamStatisticianImpl::IsPacketInOrder(uint16_t sequence_number) const { + rtc::CritScope cs(&stream_lock_); + return InOrderPacketInternal(sequence_number); +} + +bool StreamStatisticianImpl::InOrderPacketInternal( + uint16_t sequence_number) const { + // First packet is always in order. + if (last_receive_time_ms_ == 0) + return true; + + if (IsNewerSequenceNumber(sequence_number, received_seq_max_)) { + return true; + } else { + // If we have a restart of the remote side this packet is still in order. + return !IsNewerSequenceNumber(sequence_number, received_seq_max_ - + max_reordering_threshold_); + } +} + +ReceiveStatistics* ReceiveStatistics::Create(Clock* clock) { + return new ReceiveStatisticsImpl(clock); +} + +ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock) + : clock_(clock), + rtcp_stats_callback_(NULL), + rtp_stats_callback_(NULL) {} + +ReceiveStatisticsImpl::~ReceiveStatisticsImpl() { + while (!statisticians_.empty()) { + delete statisticians_.begin()->second; + statisticians_.erase(statisticians_.begin()); + } +} + +void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, + size_t packet_length, + bool retransmitted) { + StreamStatisticianImpl* impl; + { + rtc::CritScope cs(&receive_statistics_lock_); + auto it = statisticians_.find(header.ssrc); + if (it != statisticians_.end()) { + impl = it->second; + } else { + impl = new StreamStatisticianImpl(header.ssrc, clock_, this, this); + statisticians_[header.ssrc] = impl; + } + } + // StreamStatisticianImpl instance is created once and only destroyed when + // this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has + // it's own locking so don't hold receive_statistics_lock_ (potential + // deadlock). + impl->IncomingPacket(header, packet_length, retransmitted); +} + +void ReceiveStatisticsImpl::FecPacketReceived(const RTPHeader& header, + size_t packet_length) { + StreamStatisticianImpl* impl; + { + rtc::CritScope cs(&receive_statistics_lock_); + auto it = statisticians_.find(header.ssrc); + // Ignore FEC if it is the first packet. + if (it == statisticians_.end()) + return; + impl = it->second; + } + impl->FecPacketReceived(header, packet_length); +} + +StreamStatistician* ReceiveStatisticsImpl::GetStatistician( + uint32_t ssrc) const { + rtc::CritScope cs(&receive_statistics_lock_); + auto it = statisticians_.find(ssrc); + if (it == statisticians_.end()) + return NULL; + return it->second; +} + +void ReceiveStatisticsImpl::SetMaxReorderingThreshold( + int max_reordering_threshold) { + rtc::CritScope cs(&receive_statistics_lock_); + for (auto& statistician : statisticians_) { + statistician.second->SetMaxReorderingThreshold(max_reordering_threshold); + } +} + +void ReceiveStatisticsImpl::RegisterRtcpStatisticsCallback( + RtcpStatisticsCallback* callback) { + rtc::CritScope cs(&receive_statistics_lock_); + if (callback != NULL) + assert(rtcp_stats_callback_ == NULL); + rtcp_stats_callback_ = callback; +} + +void ReceiveStatisticsImpl::StatisticsUpdated(const RtcpStatistics& statistics, + uint32_t ssrc) { + rtc::CritScope cs(&receive_statistics_lock_); + if (rtcp_stats_callback_) + rtcp_stats_callback_->StatisticsUpdated(statistics, ssrc); +} + +void ReceiveStatisticsImpl::CNameChanged(const char* cname, uint32_t ssrc) { + rtc::CritScope cs(&receive_statistics_lock_); + if (rtcp_stats_callback_) + rtcp_stats_callback_->CNameChanged(cname, ssrc); +} + +void ReceiveStatisticsImpl::RegisterRtpStatisticsCallback( + StreamDataCountersCallback* callback) { + rtc::CritScope cs(&receive_statistics_lock_); + if (callback != NULL) + assert(rtp_stats_callback_ == NULL); + rtp_stats_callback_ = callback; +} + +void ReceiveStatisticsImpl::DataCountersUpdated(const StreamDataCounters& stats, + uint32_t ssrc) { + rtc::CritScope cs(&receive_statistics_lock_); + if (rtp_stats_callback_) { + rtp_stats_callback_->DataCountersUpdated(stats, ssrc); + } +} + +std::vector<rtcp::ReportBlock> ReceiveStatisticsImpl::RtcpReportBlocks( + size_t max_blocks) { + std::map<uint32_t, StreamStatisticianImpl*> statisticians; + { + rtc::CritScope cs(&receive_statistics_lock_); + statisticians = statisticians_; + } + std::vector<rtcp::ReportBlock> result; + result.reserve(std::min(max_blocks, statisticians.size())); + for (auto& statistician : statisticians) { + // TODO(danilchap): Select statistician subset across multiple calls using + // round-robin, as described in rfc3550 section 6.4 when single + // rtcp_module/receive_statistics will be used for more rtp streams. + if (result.size() == max_blocks) + break; + + // Do we have receive statistics to send? + RtcpStatistics stats; + if (!statistician.second->GetActiveStatisticsAndReset(&stats)) + continue; + result.emplace_back(); + rtcp::ReportBlock& block = result.back(); + block.SetMediaSsrc(statistician.first); + block.SetFractionLost(stats.fraction_lost); + if (!block.SetCumulativeLost(stats.packets_lost)) { + RTC_LOG(LS_WARNING) << "Cumulative lost is oversized."; + result.pop_back(); + continue; + } + block.SetExtHighestSeqNum(stats.extended_highest_sequence_number); + block.SetJitter(stats.jitter); + } + return result; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h new file mode 100644 index 0000000000..f0749a3744 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#ifndef MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_ +#define MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_ + +#include "modules/rtp_rtcp/include/receive_statistics.h" + +#include <algorithm> +#include <map> +#include <vector> + +#include "rtc_base/criticalsection.h" +#include "rtc_base/rate_statistics.h" +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { + +class StreamStatisticianImpl : public StreamStatistician { + public: + StreamStatisticianImpl(uint32_t ssrc, + Clock* clock, + RtcpStatisticsCallback* rtcp_callback, + StreamDataCountersCallback* rtp_callback); + virtual ~StreamStatisticianImpl() {} + + // |reset| here and in next method restarts calculation of fraction_lost stat. + bool GetStatistics(RtcpStatistics* statistics, bool reset) override; + bool GetActiveStatisticsAndReset(RtcpStatistics* statistics); + void GetDataCounters(size_t* bytes_received, + uint32_t* packets_received) const override; + void GetReceiveStreamDataCounters( + StreamDataCounters* data_counters) const override; + uint32_t BitrateReceived() const override; + bool IsRetransmitOfOldPacket(const RTPHeader& header, + int64_t min_rtt) const override; + bool IsPacketInOrder(uint16_t sequence_number) const override; + + void IncomingPacket(const RTPHeader& rtp_header, + size_t packet_length, + bool retransmitted); + void FecPacketReceived(const RTPHeader& header, size_t packet_length); + void SetMaxReorderingThreshold(int max_reordering_threshold); + + private: + bool InOrderPacketInternal(uint16_t sequence_number) const; + RtcpStatistics CalculateRtcpStatistics() + RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_); + void UpdateJitter(const RTPHeader& header, NtpTime receive_time); + StreamDataCounters UpdateCounters(const RTPHeader& rtp_header, + size_t packet_length, + bool retransmitted); + + const uint32_t ssrc_; + Clock* const clock_; + rtc::CriticalSection stream_lock_; + RateStatistics incoming_bitrate_; + int max_reordering_threshold_; // In number of packets or sequence numbers. + + // Stats on received RTP packets. + uint32_t jitter_q4_; + uint32_t cumulative_loss_; + + int64_t last_receive_time_ms_; + NtpTime last_receive_time_ntp_; + uint32_t last_received_timestamp_; + uint16_t received_seq_first_; + uint16_t received_seq_max_; + uint16_t received_seq_wraps_; + + // Current counter values. + size_t received_packet_overhead_; + StreamDataCounters receive_counters_; + + // Counter values when we sent the last report. + uint32_t last_report_inorder_packets_; + uint32_t last_report_old_packets_; + uint16_t last_report_seq_max_; + RtcpStatistics last_reported_statistics_; + + // stream_lock_ shouldn't be held when calling callbacks. + RtcpStatisticsCallback* const rtcp_callback_; + StreamDataCountersCallback* const rtp_callback_; +}; + +class ReceiveStatisticsImpl : public ReceiveStatistics, + public RtcpStatisticsCallback, + public StreamDataCountersCallback { + public: + explicit ReceiveStatisticsImpl(Clock* clock); + + ~ReceiveStatisticsImpl(); + + // Implement ReceiveStatisticsProvider. + std::vector<rtcp::ReportBlock> RtcpReportBlocks(size_t max_blocks) override; + + // Implement ReceiveStatistics. + void IncomingPacket(const RTPHeader& header, + size_t packet_length, + bool retransmitted) override; + void FecPacketReceived(const RTPHeader& header, + size_t packet_length) override; + StreamStatistician* GetStatistician(uint32_t ssrc) const override; + void SetMaxReorderingThreshold(int max_reordering_threshold) override; + + void RegisterRtcpStatisticsCallback( + RtcpStatisticsCallback* callback) override; + + void RegisterRtpStatisticsCallback( + StreamDataCountersCallback* callback) override; + + private: + void StatisticsUpdated(const RtcpStatistics& statistics, + uint32_t ssrc) override; + void CNameChanged(const char* cname, uint32_t ssrc) override; + void DataCountersUpdated(const StreamDataCounters& counters, + uint32_t ssrc) override; + + Clock* const clock_; + rtc::CriticalSection receive_statistics_lock_; + std::map<uint32_t, StreamStatisticianImpl*> statisticians_; + + RtcpStatisticsCallback* rtcp_stats_callback_; + StreamDataCountersCallback* rtp_stats_callback_; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc new file mode 100644 index 0000000000..a832383310 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc @@ -0,0 +1,370 @@ +/* + * 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 <memory> + +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "system_wrappers/include/clock.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +const size_t kPacketSize1 = 100; +const size_t kPacketSize2 = 300; +const uint32_t kSsrc1 = 1; +const uint32_t kSsrc2 = 2; + +class ReceiveStatisticsTest : public ::testing::Test { + public: + ReceiveStatisticsTest() : + clock_(0), + receive_statistics_(ReceiveStatistics::Create(&clock_)) { + memset(&header1_, 0, sizeof(header1_)); + header1_.ssrc = kSsrc1; + header1_.sequenceNumber = 100; + memset(&header2_, 0, sizeof(header2_)); + header2_.ssrc = kSsrc2; + header2_.sequenceNumber = 100; + } + + protected: + SimulatedClock clock_; + std::unique_ptr<ReceiveStatistics> receive_statistics_; + RTPHeader header1_; + RTPHeader header2_; +}; + +TEST_F(ReceiveStatisticsTest, TwoIncomingSsrcs) { + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + ++header1_.sequenceNumber; + receive_statistics_->IncomingPacket(header2_, kPacketSize2, false); + ++header2_.sequenceNumber; + clock_.AdvanceTimeMilliseconds(100); + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + ++header1_.sequenceNumber; + receive_statistics_->IncomingPacket(header2_, kPacketSize2, false); + ++header2_.sequenceNumber; + + StreamStatistician* statistician = + receive_statistics_->GetStatistician(kSsrc1); + ASSERT_TRUE(statistician != NULL); + EXPECT_GT(statistician->BitrateReceived(), 0u); + size_t bytes_received = 0; + uint32_t packets_received = 0; + statistician->GetDataCounters(&bytes_received, &packets_received); + EXPECT_EQ(200u, bytes_received); + EXPECT_EQ(2u, packets_received); + + statistician = + receive_statistics_->GetStatistician(kSsrc2); + ASSERT_TRUE(statistician != NULL); + EXPECT_GT(statistician->BitrateReceived(), 0u); + statistician->GetDataCounters(&bytes_received, &packets_received); + EXPECT_EQ(600u, bytes_received); + EXPECT_EQ(2u, packets_received); + + EXPECT_EQ(2u, receive_statistics_->RtcpReportBlocks(3).size()); + // Add more incoming packets and verify that they are registered in both + // access methods. + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + ++header1_.sequenceNumber; + receive_statistics_->IncomingPacket(header2_, kPacketSize2, false); + ++header2_.sequenceNumber; + + receive_statistics_->GetStatistician(kSsrc1)->GetDataCounters( + &bytes_received, &packets_received); + EXPECT_EQ(300u, bytes_received); + EXPECT_EQ(3u, packets_received); + receive_statistics_->GetStatistician(kSsrc2)->GetDataCounters( + &bytes_received, &packets_received); + EXPECT_EQ(900u, bytes_received); + EXPECT_EQ(3u, packets_received); +} + +TEST_F(ReceiveStatisticsTest, ActiveStatisticians) { + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + ++header1_.sequenceNumber; + clock_.AdvanceTimeMilliseconds(1000); + receive_statistics_->IncomingPacket(header2_, kPacketSize2, false); + ++header2_.sequenceNumber; + // Nothing should time out since only 1000 ms has passed since the first + // packet came in. + EXPECT_EQ(2u, receive_statistics_->RtcpReportBlocks(3).size()); + + clock_.AdvanceTimeMilliseconds(7000); + // kSsrc1 should have timed out. + EXPECT_EQ(1u, receive_statistics_->RtcpReportBlocks(3).size()); + + clock_.AdvanceTimeMilliseconds(1000); + // kSsrc2 should have timed out. + EXPECT_EQ(0u, receive_statistics_->RtcpReportBlocks(3).size()); + + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + ++header1_.sequenceNumber; + // kSsrc1 should be active again and the data counters should have survived. + EXPECT_EQ(1u, receive_statistics_->RtcpReportBlocks(3).size()); + StreamStatistician* statistician = + receive_statistics_->GetStatistician(kSsrc1); + ASSERT_TRUE(statistician != NULL); + size_t bytes_received = 0; + uint32_t packets_received = 0; + statistician->GetDataCounters(&bytes_received, &packets_received); + EXPECT_EQ(200u, bytes_received); + EXPECT_EQ(2u, packets_received); +} + +TEST_F(ReceiveStatisticsTest, GetReceiveStreamDataCounters) { + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + StreamStatistician* statistician = + receive_statistics_->GetStatistician(kSsrc1); + ASSERT_TRUE(statistician != NULL); + + StreamDataCounters counters; + statistician->GetReceiveStreamDataCounters(&counters); + EXPECT_GT(counters.first_packet_time_ms, -1); + EXPECT_EQ(1u, counters.transmitted.packets); + + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + statistician->GetReceiveStreamDataCounters(&counters); + EXPECT_GT(counters.first_packet_time_ms, -1); + EXPECT_EQ(2u, counters.transmitted.packets); +} + +TEST_F(ReceiveStatisticsTest, RtcpCallbacks) { + class TestCallback : public RtcpStatisticsCallback { + public: + TestCallback() + : RtcpStatisticsCallback(), num_calls_(0), ssrc_(0), stats_() {} + virtual ~TestCallback() {} + + void StatisticsUpdated(const RtcpStatistics& statistics, + uint32_t ssrc) override { + ssrc_ = ssrc; + stats_ = statistics; + ++num_calls_; + } + + void CNameChanged(const char* cname, uint32_t ssrc) override {} + + uint32_t num_calls_; + uint32_t ssrc_; + RtcpStatistics stats_; + } callback; + + receive_statistics_->RegisterRtcpStatisticsCallback(&callback); + + // Add some arbitrary data, with loss and jitter. + header1_.sequenceNumber = 1; + clock_.AdvanceTimeMilliseconds(7); + header1_.timestamp += 3; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + header1_.sequenceNumber += 2; + clock_.AdvanceTimeMilliseconds(9); + header1_.timestamp += 9; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + --header1_.sequenceNumber; + clock_.AdvanceTimeMilliseconds(13); + header1_.timestamp += 47; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, true); + header1_.sequenceNumber += 3; + clock_.AdvanceTimeMilliseconds(11); + header1_.timestamp += 17; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + ++header1_.sequenceNumber; + + EXPECT_EQ(0u, callback.num_calls_); + + // Call GetStatistics, simulating a timed rtcp sender thread. + RtcpStatistics statistics; + receive_statistics_->GetStatistician(kSsrc1) + ->GetStatistics(&statistics, true); + + EXPECT_EQ(1u, callback.num_calls_); + EXPECT_EQ(callback.ssrc_, kSsrc1); + EXPECT_EQ(statistics.packets_lost, callback.stats_.packets_lost); + EXPECT_EQ(statistics.extended_highest_sequence_number, + callback.stats_.extended_highest_sequence_number); + EXPECT_EQ(statistics.fraction_lost, callback.stats_.fraction_lost); + EXPECT_EQ(statistics.jitter, callback.stats_.jitter); + EXPECT_EQ(51, statistics.fraction_lost); + EXPECT_EQ(1u, statistics.packets_lost); + EXPECT_EQ(5u, statistics.extended_highest_sequence_number); + EXPECT_EQ(4u, statistics.jitter); + + receive_statistics_->RegisterRtcpStatisticsCallback(NULL); + + // Add some more data. + header1_.sequenceNumber = 1; + clock_.AdvanceTimeMilliseconds(7); + header1_.timestamp += 3; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + header1_.sequenceNumber += 2; + clock_.AdvanceTimeMilliseconds(9); + header1_.timestamp += 9; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + --header1_.sequenceNumber; + clock_.AdvanceTimeMilliseconds(13); + header1_.timestamp += 47; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, true); + header1_.sequenceNumber += 3; + clock_.AdvanceTimeMilliseconds(11); + header1_.timestamp += 17; + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + ++header1_.sequenceNumber; + + receive_statistics_->GetStatistician(kSsrc1) + ->GetStatistics(&statistics, true); + + // Should not have been called after deregister. + EXPECT_EQ(1u, callback.num_calls_); +} + +class RtpTestCallback : public StreamDataCountersCallback { + public: + RtpTestCallback() + : StreamDataCountersCallback(), num_calls_(0), ssrc_(0), stats_() {} + virtual ~RtpTestCallback() {} + + virtual void DataCountersUpdated(const StreamDataCounters& counters, + uint32_t ssrc) { + ssrc_ = ssrc; + stats_ = counters; + ++num_calls_; + } + + void MatchPacketCounter(const RtpPacketCounter& expected, + const RtpPacketCounter& actual) { + EXPECT_EQ(expected.payload_bytes, actual.payload_bytes); + EXPECT_EQ(expected.header_bytes, actual.header_bytes); + EXPECT_EQ(expected.padding_bytes, actual.padding_bytes); + EXPECT_EQ(expected.packets, actual.packets); + } + + void Matches(uint32_t num_calls, + uint32_t ssrc, + const StreamDataCounters& expected) { + EXPECT_EQ(num_calls, num_calls_); + EXPECT_EQ(ssrc, ssrc_); + MatchPacketCounter(expected.transmitted, stats_.transmitted); + MatchPacketCounter(expected.retransmitted, stats_.retransmitted); + MatchPacketCounter(expected.fec, stats_.fec); + } + + uint32_t num_calls_; + uint32_t ssrc_; + StreamDataCounters stats_; +}; + +TEST_F(ReceiveStatisticsTest, RtpCallbacks) { + RtpTestCallback callback; + receive_statistics_->RegisterRtpStatisticsCallback(&callback); + + const size_t kHeaderLength = 20; + const size_t kPaddingLength = 9; + + // One packet of size kPacketSize1. + header1_.headerLength = kHeaderLength; + receive_statistics_->IncomingPacket( + header1_, kPacketSize1 + kHeaderLength, false); + StreamDataCounters expected; + expected.transmitted.payload_bytes = kPacketSize1; + expected.transmitted.header_bytes = kHeaderLength; + expected.transmitted.padding_bytes = 0; + expected.transmitted.packets = 1; + expected.retransmitted.payload_bytes = 0; + expected.retransmitted.header_bytes = 0; + expected.retransmitted.padding_bytes = 0; + expected.retransmitted.packets = 0; + expected.fec.packets = 0; + callback.Matches(1, kSsrc1, expected); + + ++header1_.sequenceNumber; + clock_.AdvanceTimeMilliseconds(5); + header1_.paddingLength = 9; + // Another packet of size kPacketSize1 with 9 bytes padding. + receive_statistics_->IncomingPacket( + header1_, kPacketSize1 + kHeaderLength + kPaddingLength, false); + expected.transmitted.payload_bytes = kPacketSize1 * 2; + expected.transmitted.header_bytes = kHeaderLength * 2; + expected.transmitted.padding_bytes = kPaddingLength; + expected.transmitted.packets = 2; + callback.Matches(2, kSsrc1, expected); + + clock_.AdvanceTimeMilliseconds(5); + // Retransmit last packet. + receive_statistics_->IncomingPacket( + header1_, kPacketSize1 + kHeaderLength + kPaddingLength, true); + expected.transmitted.payload_bytes = kPacketSize1 * 3; + expected.transmitted.header_bytes = kHeaderLength * 3; + expected.transmitted.padding_bytes = kPaddingLength * 2; + expected.transmitted.packets = 3; + expected.retransmitted.payload_bytes = kPacketSize1; + expected.retransmitted.header_bytes = kHeaderLength; + expected.retransmitted.padding_bytes = kPaddingLength; + expected.retransmitted.packets = 1; + callback.Matches(3, kSsrc1, expected); + + header1_.paddingLength = 0; + ++header1_.sequenceNumber; + clock_.AdvanceTimeMilliseconds(5); + // One FEC packet. + receive_statistics_->IncomingPacket( + header1_, kPacketSize1 + kHeaderLength, false); + receive_statistics_->FecPacketReceived(header1_, + kPacketSize1 + kHeaderLength); + expected.transmitted.payload_bytes = kPacketSize1 * 4; + expected.transmitted.header_bytes = kHeaderLength * 4; + expected.transmitted.packets = 4; + expected.fec.payload_bytes = kPacketSize1; + expected.fec.header_bytes = kHeaderLength; + expected.fec.packets = 1; + callback.Matches(5, kSsrc1, expected); + + receive_statistics_->RegisterRtpStatisticsCallback(NULL); + + // New stats, but callback should not be called. + ++header1_.sequenceNumber; + clock_.AdvanceTimeMilliseconds(5); + receive_statistics_->IncomingPacket( + header1_, kPacketSize1 + kHeaderLength, true); + callback.Matches(5, kSsrc1, expected); +} + +TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) { + RtpTestCallback callback; + receive_statistics_->RegisterRtpStatisticsCallback(&callback); + + const uint32_t kHeaderLength = 20; + header1_.headerLength = kHeaderLength; + + // If first packet is FEC, ignore it. + receive_statistics_->FecPacketReceived(header1_, + kPacketSize1 + kHeaderLength); + EXPECT_EQ(0u, callback.num_calls_); + + receive_statistics_->IncomingPacket( + header1_, kPacketSize1 + kHeaderLength, false); + StreamDataCounters expected; + expected.transmitted.payload_bytes = kPacketSize1; + expected.transmitted.header_bytes = kHeaderLength; + expected.transmitted.padding_bytes = 0; + expected.transmitted.packets = 1; + expected.fec.packets = 0; + callback.Matches(1, kSsrc1, expected); + + receive_statistics_->FecPacketReceived(header1_, + kPacketSize1 + kHeaderLength); + expected.fec.payload_bytes = kPacketSize1; + expected.fec.header_bytes = kHeaderLength; + expected.fec.packets = 1; + callback.Matches(2, kSsrc1, expected); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc new file mode 100644 index 0000000000..e3a4ed91e5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc @@ -0,0 +1,83 @@ +/* + * 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/rtp_rtcp/include/remote_ntp_time_estimator.h" + +#include "rtc_base/logging.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +namespace { +static const int kTimingLogIntervalMs = 10000; +static const int kClocksOffsetSmoothingWindow = 100; + +} // namespace + +// TODO(wu): Refactor this class so that it can be shared with +// vie_sync_module.cc. +RemoteNtpTimeEstimator::RemoteNtpTimeEstimator(Clock* clock) + : clock_(clock), + ntp_clocks_offset_estimator_(kClocksOffsetSmoothingWindow), + last_timing_log_ms_(-1) {} + +RemoteNtpTimeEstimator::~RemoteNtpTimeEstimator() {} + +bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt, + uint32_t ntp_secs, + uint32_t ntp_frac, + uint32_t rtcp_timestamp) { + bool new_rtcp_sr = false; + if (!rtp_to_ntp_.UpdateMeasurements(ntp_secs, ntp_frac, rtcp_timestamp, + &new_rtcp_sr)) { + return false; + } + if (!new_rtcp_sr) { + // No new RTCP SR since last time this function was called. + return true; + } + + // Update extrapolator with the new arrival time. + // The extrapolator assumes the TimeInMilliseconds time. + int64_t receiver_arrival_time_ms = clock_->TimeInMilliseconds(); + int64_t sender_send_time_ms = Clock::NtpToMs(ntp_secs, ntp_frac); + int64_t sender_arrival_time_ms = sender_send_time_ms + rtt / 2; + int64_t remote_to_local_clocks_offset = + receiver_arrival_time_ms - sender_arrival_time_ms; + ntp_clocks_offset_estimator_.Insert(remote_to_local_clocks_offset); + return true; +} + +int64_t RemoteNtpTimeEstimator::Estimate(uint32_t rtp_timestamp) { + int64_t sender_capture_ntp_ms = 0; + if (!rtp_to_ntp_.Estimate(rtp_timestamp, &sender_capture_ntp_ms)) { + return -1; + } + + int64_t remote_to_local_clocks_offset = + ntp_clocks_offset_estimator_.GetFilteredValue(); + int64_t receiver_capture_ms = + sender_capture_ntp_ms + remote_to_local_clocks_offset; + int64_t now_ms = clock_->TimeInMilliseconds(); + int64_t ntp_offset = clock_->CurrentNtpInMilliseconds() - now_ms; + int64_t receiver_capture_ntp_ms = receiver_capture_ms + ntp_offset; + + if (now_ms - last_timing_log_ms_ > kTimingLogIntervalMs) { + RTC_LOG(LS_INFO) << "RTP timestamp: " << rtp_timestamp + << " in NTP clock: " << sender_capture_ntp_ms + << " estimated time in receiver clock: " + << receiver_capture_ms + << " converted to NTP clock: " << receiver_capture_ntp_ms; + last_timing_log_ms_ = now_ms; + } + return receiver_capture_ntp_ms; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc new file mode 100644 index 0000000000..24eb46f767 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc @@ -0,0 +1,144 @@ +/* +* 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/rtp_rtcp/include/remote_ntp_time_estimator.h" +#include "common_types.h" // NOLINT(build/include) +#include "system_wrappers/include/clock.h" +#include "test/gmock.h" +#include "test/gtest.h" + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Return; +using ::testing::SetArgPointee; + +namespace webrtc { + +static const int64_t kTestRtt = 10; +static const int64_t kLocalClockInitialTimeMs = 123; +static const int64_t kRemoteClockInitialTimeMs = 345; +static const uint32_t kTimestampOffset = 567; + +class RemoteNtpTimeEstimatorTest : public ::testing::Test { + protected: + RemoteNtpTimeEstimatorTest() + : local_clock_(kLocalClockInitialTimeMs * 1000), + remote_clock_(kRemoteClockInitialTimeMs * 1000), + estimator_(new RemoteNtpTimeEstimator(&local_clock_)) {} + ~RemoteNtpTimeEstimatorTest() {} + + void AdvanceTimeMilliseconds(int64_t ms) { + local_clock_.AdvanceTimeMilliseconds(ms); + remote_clock_.AdvanceTimeMilliseconds(ms); + } + + uint32_t GetRemoteTimestamp() { + return static_cast<uint32_t>(remote_clock_.TimeInMilliseconds()) * 90 + + kTimestampOffset; + } + + void SendRtcpSr() { + uint32_t rtcp_timestamp = GetRemoteTimestamp(); + NtpTime ntp = remote_clock_.CurrentNtpTime(); + + AdvanceTimeMilliseconds(kTestRtt / 2); + ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions()); + } + + void SendRtcpSrInaccurately(int64_t ntp_error_ms, + int64_t networking_delay_ms) { + uint32_t rtcp_timestamp = GetRemoteTimestamp(); + int64_t ntp_error_fractions = + ntp_error_ms * NtpTime::kFractionsPerSecond / 1000; + NtpTime ntp(static_cast<uint64_t>(remote_clock_.CurrentNtpTime()) + + ntp_error_fractions); + AdvanceTimeMilliseconds(kTestRtt / 2 + networking_delay_ms); + ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions()); + } + + void UpdateRtcpTimestamp(int64_t rtt, uint32_t ntp_secs, uint32_t ntp_frac, + uint32_t rtp_timestamp, bool expected_result) { + EXPECT_EQ(expected_result, estimator_->UpdateRtcpTimestamp( + rtt, ntp_secs, ntp_frac, rtp_timestamp)); + } + + void ReceiveRtcpSr(int64_t rtt, + uint32_t rtcp_timestamp, + uint32_t ntp_seconds, + uint32_t ntp_fractions) { + UpdateRtcpTimestamp(rtt, ntp_seconds, ntp_fractions, rtcp_timestamp, true); + } + + SimulatedClock local_clock_; + SimulatedClock remote_clock_; + std::unique_ptr<RemoteNtpTimeEstimator> estimator_; +}; + +TEST_F(RemoteNtpTimeEstimatorTest, Estimate) { + // Failed without valid NTP. + UpdateRtcpTimestamp(kTestRtt, 0, 0, 0, false); + + AdvanceTimeMilliseconds(1000); + // Remote peer sends first RTCP SR. + SendRtcpSr(); + + // Remote sends a RTP packet. + AdvanceTimeMilliseconds(15); + uint32_t rtp_timestamp = GetRemoteTimestamp(); + int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds(); + + // Local peer needs at least 2 RTCP SR to calculate the capture time. + const int64_t kNotEnoughRtcpSr = -1; + EXPECT_EQ(kNotEnoughRtcpSr, estimator_->Estimate(rtp_timestamp)); + + AdvanceTimeMilliseconds(800); + // Remote sends second RTCP SR. + SendRtcpSr(); + + // Local peer gets enough RTCP SR to calculate the capture time. + EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp)); +} + +TEST_F(RemoteNtpTimeEstimatorTest, AveragesErrorsOut) { + // Remote peer sends first 5 RTCP SR without errors. + AdvanceTimeMilliseconds(1000); + SendRtcpSr(); + AdvanceTimeMilliseconds(1000); + SendRtcpSr(); + AdvanceTimeMilliseconds(1000); + SendRtcpSr(); + AdvanceTimeMilliseconds(1000); + SendRtcpSr(); + AdvanceTimeMilliseconds(1000); + SendRtcpSr(); + + AdvanceTimeMilliseconds(15); + uint32_t rtp_timestamp = GetRemoteTimestamp(); + int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds(); + + // Local peer gets enough RTCP SR to calculate the capture time. + EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp)); + + // Remote sends corrupted RTCP SRs + AdvanceTimeMilliseconds(1000); + SendRtcpSrInaccurately(10, 10); + AdvanceTimeMilliseconds(1000); + SendRtcpSrInaccurately(-20, 5); + + // New RTP packet to estimate timestamp. + AdvanceTimeMilliseconds(150); + rtp_timestamp = GetRemoteTimestamp(); + capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds(); + + // Errors should be averaged out. + EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.cc new file mode 100644 index 0000000000..8700b045b9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtcp_nack_stats.h" + +#include "modules/include/module_common_types.h" + +namespace webrtc { + +RtcpNackStats::RtcpNackStats() + : max_sequence_number_(0), + requests_(0), + unique_requests_(0) {} + +void RtcpNackStats::ReportRequest(uint16_t sequence_number) { + if (requests_ == 0 || + IsNewerSequenceNumber(sequence_number, max_sequence_number_)) { + max_sequence_number_ = sequence_number; + ++unique_requests_; + } + ++requests_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.h new file mode 100644 index 0000000000..d9e2622abc --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.h @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2017 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_RTP_RTCP_SOURCE_RTCP_NACK_STATS_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_NACK_STATS_H_ + +#include <stdint.h> + +namespace webrtc { + +class RtcpNackStats { + public: + RtcpNackStats(); + + // Updates stats with requested sequence number. + // This function should be called for each NACK request to calculate the + // number of unique NACKed RTP packets. + void ReportRequest(uint16_t sequence_number); + + // Gets the number of NACKed RTP packets. + uint32_t requests() const { return requests_; } + + // Gets the number of unique NACKed RTP packets. + uint32_t unique_requests() const { return unique_requests_; } + + private: + uint16_t max_sequence_number_; + uint32_t requests_; + uint32_t unique_requests_; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_NACK_STATS_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats_unittest.cc new file mode 100644 index 0000000000..5b4def5476 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats_unittest.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtcp_nack_stats.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(RtcpNackStatsTest, Requests) { + RtcpNackStats stats; + EXPECT_EQ(0U, stats.unique_requests()); + EXPECT_EQ(0U, stats.requests()); + stats.ReportRequest(10); + EXPECT_EQ(1U, stats.unique_requests()); + EXPECT_EQ(1U, stats.requests()); + + stats.ReportRequest(10); + EXPECT_EQ(1U, stats.unique_requests()); + stats.ReportRequest(11); + EXPECT_EQ(2U, stats.unique_requests()); + + stats.ReportRequest(11); + EXPECT_EQ(2U, stats.unique_requests()); + stats.ReportRequest(13); + EXPECT_EQ(3U, stats.unique_requests()); + + stats.ReportRequest(11); + EXPECT_EQ(3U, stats.unique_requests()); + EXPECT_EQ(6U, stats.requests()); +} + +TEST(RtcpNackStatsTest, RequestsWithWrap) { + RtcpNackStats stats; + stats.ReportRequest(65534); + EXPECT_EQ(1U, stats.unique_requests()); + + stats.ReportRequest(65534); + EXPECT_EQ(1U, stats.unique_requests()); + stats.ReportRequest(65535); + EXPECT_EQ(2U, stats.unique_requests()); + + stats.ReportRequest(65535); + EXPECT_EQ(2U, stats.unique_requests()); + stats.ReportRequest(0); + EXPECT_EQ(3U, stats.unique_requests()); + + stats.ReportRequest(65535); + EXPECT_EQ(3U, stats.unique_requests()); + stats.ReportRequest(0); + EXPECT_EQ(3U, stats.unique_requests()); + stats.ReportRequest(1); + EXPECT_EQ(4U, stats.unique_requests()); + EXPECT_EQ(8U, stats.requests()); +} + +} // namespace webrtc + diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc new file mode 100644 index 0000000000..4c67f60987 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc @@ -0,0 +1,86 @@ +/* + * 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/rtp_rtcp/source/rtcp_packet.h" + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace rtcp { +constexpr size_t RtcpPacket::kHeaderLength; + +rtc::Buffer RtcpPacket::Build() const { + rtc::Buffer packet(BlockLength()); + + size_t length = 0; + bool created = Create(packet.data(), &length, packet.capacity(), nullptr); + RTC_DCHECK(created) << "Invalid packet is not supported."; + RTC_DCHECK_EQ(length, packet.size()) + << "BlockLength mispredicted size used by Create"; + + return packet; +} + +bool RtcpPacket::BuildExternalBuffer(uint8_t* buffer, + size_t max_length, + PacketReadyCallback* callback) const { + size_t index = 0; + if (!Create(buffer, &index, max_length, callback)) + return false; + return OnBufferFull(buffer, &index, callback); +} + +bool RtcpPacket::OnBufferFull(uint8_t* packet, + size_t* index, + PacketReadyCallback* callback) const { + if (*index == 0) + return false; + RTC_DCHECK(callback) << "Fragmentation not supported."; + callback->OnPacketReady(packet, *index); + *index = 0; + return true; +} + +size_t RtcpPacket::HeaderLength() const { + size_t length_in_bytes = BlockLength(); + RTC_DCHECK_GT(length_in_bytes, 0); + RTC_DCHECK_EQ(length_in_bytes % 4, 0) << "Padding not supported"; + // Length in 32-bit words without common header. + return (length_in_bytes - kHeaderLength) / 4; +} + +// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications. +// +// RTP header format. +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC/FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +void RtcpPacket::CreateHeader( + size_t count_or_format, // Depends on packet type. + uint8_t packet_type, + size_t length, + uint8_t* buffer, + size_t* pos) { + RTC_DCHECK_LE(length, 0xffffU); + RTC_DCHECK_LE(count_or_format, 0x1f); + constexpr uint8_t kVersionBits = 2 << 6; + constexpr uint8_t kNoPaddingBit = 0 << 5; + buffer[*pos + 0] = kVersionBits | kNoPaddingBit | + static_cast<uint8_t>(count_or_format); + buffer[*pos + 1] = packet_type; + buffer[*pos + 2] = (length >> 8) & 0xff; + buffer[*pos + 3] = length & 0xff; + *pos += kHeaderLength; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.h new file mode 100644 index 0000000000..248f47c19c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.h @@ -0,0 +1,103 @@ +/* + * 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_RTP_RTCP_SOURCE_RTCP_PACKET_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_H_ + +#include "rtc_base/basictypes.h" +#include "rtc_base/buffer.h" + +namespace webrtc { +namespace rtcp { +// Class for building RTCP packets. +// +// Example: +// ReportBlock report_block; +// report_block.SetMediaSsrc(234); +// report_block.SetFractionLost(10); +// +// ReceiverReport rr; +// rr.SetSenderSsrc(123); +// rr.AddReportBlock(report_block); +// +// Fir fir; +// fir.SetSenderSsrc(123); +// fir.AddRequestTo(234, 56); +// +// size_t length = 0; // Builds an intra frame request +// uint8_t packet[kPacketSize]; // with sequence number 56. +// fir.Build(packet, &length, kPacketSize); +// +// rtc::Buffer packet = fir.Build(); // Returns a RawPacket holding +// // the built rtcp packet. +// +// CompoundPacket compound; // Builds a compound RTCP packet with +// compound.Append(&rr); // a receiver report, report block +// compound.Append(&fir); // and fir message. +// rtc::Buffer packet = compound.Build(); + +class RtcpPacket { + public: + // Callback used to signal that an RTCP packet is ready. Note that this may + // not contain all data in this RtcpPacket; if a packet cannot fit in + // max_length bytes, it will be fragmented and multiple calls to this + // callback will be made. + class PacketReadyCallback { + public: + virtual void OnPacketReady(uint8_t* data, size_t length) = 0; + + protected: + PacketReadyCallback() {} + virtual ~PacketReadyCallback() {} + }; + + virtual ~RtcpPacket() {} + + // Convenience method mostly used for test. Creates packet without + // fragmentation using BlockLength() to allocate big enough buffer. + rtc::Buffer Build() const; + + // Returns true if call to Create succeeded. Provided buffer reference + // will be used for all calls to callback. + bool BuildExternalBuffer(uint8_t* buffer, + size_t max_length, + PacketReadyCallback* callback) const; + + // Size of this packet in bytes (including headers). + virtual size_t BlockLength() const = 0; + + // Creates packet in the given buffer at the given position. + // Calls PacketReadyCallback::OnPacketReady if remaining buffer is too small + // and assume buffer can be reused after OnPacketReady returns. + virtual bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + PacketReadyCallback* callback) const = 0; + + protected: + // Size of the rtcp common header. + static constexpr size_t kHeaderLength = 4; + RtcpPacket() {} + + static void CreateHeader(size_t count_or_format, + uint8_t packet_type, + size_t block_length, // Payload size in 32bit words. + uint8_t* buffer, + size_t* pos); + + bool OnBufferFull(uint8_t* packet, + size_t* index, + PacketReadyCallback* callback) const; + // Size of the rtcp packet as written in header. + size_t HeaderLength() const; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc new file mode 100644 index 0000000000..6ef97fa05a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/app.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t App::kPacketType; +constexpr size_t App::kMaxDataSize; +// Application-Defined packet (APP) (RFC 3550). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| subtype | PT=APP=204 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC/CSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | name (ASCII) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | application-dependent data ... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +App::App() : sub_type_(0), ssrc_(0), name_(0) {} + +App::~App() = default; + +bool App::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + if (packet.payload_size_bytes() < kAppBaseLength) { + RTC_LOG(LS_WARNING) << "Packet is too small to be a valid APP packet"; + return false; + } + if (packet.payload_size_bytes() % 4 != 0) { + RTC_LOG(LS_WARNING) + << "Packet payload must be 32 bits aligned to make a valid APP packet"; + return false; + } + sub_type_ = packet.fmt(); + ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&packet.payload()[0]); + name_ = ByteReader<uint32_t>::ReadBigEndian(&packet.payload()[4]); + data_.SetData(packet.payload() + kAppBaseLength, + packet.payload_size_bytes() - kAppBaseLength); + return true; +} + +void App::SetSubType(uint8_t subtype) { + RTC_DCHECK_LE(subtype, 0x1f); + sub_type_ = subtype; +} + +void App::SetData(const uint8_t* data, size_t data_length) { + RTC_DCHECK(data); + RTC_DCHECK_EQ(data_length % 4, 0) << "Data must be 32 bits aligned."; + RTC_DCHECK_LE(data_length, kMaxDataSize) << "App data size " << data_length + << " exceed maximum of " + << kMaxDataSize << " bytes."; + data_.SetData(data, data_length); +} + +size_t App::BlockLength() const { + return kHeaderLength + kAppBaseLength + data_.size(); +} + +bool App::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + CreateHeader(sub_type_, kPacketType, HeaderLength(), packet, index); + + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], ssrc_); + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 4], name_); + memcpy(&packet[*index + 8], data_.data(), data_.size()); + *index += (8 + data_.size()); + RTC_DCHECK_EQ(index_end, *index); + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h new file mode 100644 index 0000000000..3b6418d3df --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h @@ -0,0 +1,60 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_ + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "rtc_base/buffer.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +class App : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 204; + App(); + ~App() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void SetSsrc(uint32_t ssrc) { ssrc_ = ssrc; } + void SetSubType(uint8_t subtype); + void SetName(uint32_t name) { name_ = name; } + void SetData(const uint8_t* data, size_t data_length); + + uint8_t sub_type() const { return sub_type_; } + uint32_t ssrc() const { return ssrc_; } + uint32_t name() const { return name_; } + size_t data_size() const { return data_.size(); } + const uint8_t* data() const { return data_.data(); } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static constexpr size_t kAppBaseLength = 8; // Ssrc and Name. + static constexpr size_t kMaxDataSize = 0xffff * 4 - kAppBaseLength; + + uint8_t sub_type_; + uint32_t ssrc_; + uint32_t name_; + rtc::Buffer data_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc new file mode 100644 index 0000000000..59356e58aa --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/app.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +namespace webrtc { +namespace { + +using ::testing::ElementsAreArray; +using ::testing::make_tuple; +using ::webrtc::rtcp::App; + +constexpr uint32_t kName = ((uint32_t)'n' << 24) | ((uint32_t)'a' << 16) | + ((uint32_t)'m' << 8) | (uint32_t)'e'; +constexpr uint8_t kSubtype = 0x1e; +constexpr uint32_t kSenderSsrc = 0x12345678; +constexpr uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'}; +constexpr uint8_t kVersionBits = 2 << 6; +constexpr uint8_t kPaddingBit = 1 << 5; +// clang-format off +constexpr uint8_t kPacketWithoutData[] = { + kVersionBits | kSubtype, App::kPacketType, 0x00, 0x02, + 0x12, 0x34, 0x56, 0x78, + 'n', 'a', 'm', 'e'}; +constexpr uint8_t kPacketWithData[] = { + kVersionBits | kSubtype, App::kPacketType, 0x00, 0x04, + 0x12, 0x34, 0x56, 0x78, + 'n', 'a', 'm', 'e', + 't', 'e', 's', 't', + 'd', 'a', 't', 'a'}; +constexpr uint8_t kTooSmallPacket[] = { + kVersionBits | kSubtype, App::kPacketType, 0x00, 0x01, + 0x12, 0x34, 0x56, 0x78}; +constexpr uint8_t kPaddingSize = 1; +constexpr uint8_t kPacketWithUnalignedPayload[] = { + kVersionBits | kPaddingBit | kSubtype, App::kPacketType, 0x00, 0x03, + 0x12, 0x34, 0x56, 0x78, + 'n', 'a', 'm', 'e', + 'd', 'a', 't', kPaddingSize}; +// clang-format on +} // namespace + +TEST(RtcpPacketAppTest, CreateWithoutData) { + App app; + app.SetSsrc(kSenderSsrc); + app.SetSubType(kSubtype); + app.SetName(kName); + + rtc::Buffer raw = app.Build(); + + EXPECT_THAT(make_tuple(raw.data(), raw.size()), + ElementsAreArray(kPacketWithoutData)); +} + +TEST(RtcpPacketAppTest, ParseWithoutData) { + App parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacketWithoutData, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.ssrc()); + EXPECT_EQ(kSubtype, parsed.sub_type()); + EXPECT_EQ(kName, parsed.name()); + EXPECT_EQ(0u, parsed.data_size()); +} + +TEST(RtcpPacketAppTest, CreateWithData) { + App app; + app.SetSsrc(kSenderSsrc); + app.SetSubType(kSubtype); + app.SetName(kName); + app.SetData(kData, sizeof(kData)); + + rtc::Buffer raw = app.Build(); + + EXPECT_THAT(make_tuple(raw.data(), raw.size()), + ElementsAreArray(kPacketWithData)); +} + +TEST(RtcpPacketAppTest, ParseWithData) { + App parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacketWithData, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.ssrc()); + EXPECT_EQ(kSubtype, parsed.sub_type()); + EXPECT_EQ(kName, parsed.name()); + EXPECT_THAT(make_tuple(parsed.data(), parsed.data_size()), + ElementsAreArray(kData)); +} + +TEST(RtcpPacketAppTest, ParseFailsOnTooSmallPacket) { + App parsed; + EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed)); +} + +TEST(RtcpPacketAppTest, ParseFailsOnUnalignedPayload) { + App parsed; + EXPECT_FALSE(test::ParseSinglePacket(kPacketWithUnalignedPayload, &parsed)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc new file mode 100644 index 0000000000..11d87ef641 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Bye::kPacketType; +// Bye packet (BYE) (RFC 3550). +// +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| SC | PT=BYE=203 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC/CSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : ... : +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// (opt) | length | reason for leaving ... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Bye::Bye() : sender_ssrc_(0) {} + +Bye::~Bye() = default; + +bool Bye::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + + const uint8_t src_count = packet.count(); + // Validate packet. + if (packet.payload_size_bytes() < 4u * src_count) { + RTC_LOG(LS_WARNING) + << "Packet is too small to contain CSRCs it promise to have."; + return false; + } + const uint8_t* const payload = packet.payload(); + bool has_reason = packet.payload_size_bytes() > 4u * src_count; + uint8_t reason_length = 0; + if (has_reason) { + reason_length = payload[4u * src_count]; + if (packet.payload_size_bytes() - 4u * src_count < 1u + reason_length) { + RTC_LOG(LS_WARNING) << "Invalid reason length: " << reason_length; + return false; + } + } + // Once sure packet is valid, copy values. + if (src_count == 0) { // A count value of zero is valid, but useless. + sender_ssrc_ = 0; + csrcs_.clear(); + } else { + sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload); + csrcs_.resize(src_count - 1); + for (size_t i = 1; i < src_count; ++i) + csrcs_[i - 1] = ByteReader<uint32_t>::ReadBigEndian(&payload[4 * i]); + } + + if (has_reason) { + reason_.assign(reinterpret_cast<const char*>(&payload[4u * src_count + 1]), + reason_length); + } else { + reason_.clear(); + } + + return true; +} + +bool Bye::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + + CreateHeader(1 + csrcs_.size(), kPacketType, HeaderLength(), packet, index); + // Store srcs of the leaving clients. + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], sender_ssrc_); + *index += sizeof(uint32_t); + for (uint32_t csrc : csrcs_) { + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], csrc); + *index += sizeof(uint32_t); + } + // Store the reason to leave. + if (!reason_.empty()) { + uint8_t reason_length = static_cast<uint8_t>(reason_.size()); + packet[(*index)++] = reason_length; + memcpy(&packet[*index], reason_.data(), reason_length); + *index += reason_length; + // Add padding bytes if needed. + size_t bytes_to_pad = index_end - *index; + RTC_DCHECK_LE(bytes_to_pad, 3); + if (bytes_to_pad > 0) { + memset(&packet[*index], 0, bytes_to_pad); + *index += bytes_to_pad; + } + } + RTC_DCHECK_EQ(index_end, *index); + return true; +} + +bool Bye::SetCsrcs(std::vector<uint32_t> csrcs) { + if (csrcs.size() > kMaxNumberOfCsrcs) { + RTC_LOG(LS_WARNING) << "Too many CSRCs for Bye packet."; + return false; + } + csrcs_ = std::move(csrcs); + return true; +} + +void Bye::SetReason(std::string reason) { + RTC_DCHECK_LE(reason.size(), 0xffu); + reason_ = std::move(reason); +} + +size_t Bye::BlockLength() const { + size_t src_count = (1 + csrcs_.size()); + size_t reason_size_in_32bits = reason_.empty() ? 0 : (reason_.size() / 4 + 1); + return kHeaderLength + 4 * (src_count + reason_size_in_32bits); +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h new file mode 100644 index 0000000000..0cfc53475e --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h @@ -0,0 +1,59 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_ + +#include <string> +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +class Bye : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 203; + + Bye(); + ~Bye() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; } + bool SetCsrcs(std::vector<uint32_t> csrcs); + void SetReason(std::string reason); + + uint32_t sender_ssrc() const { return sender_ssrc_; } + const std::vector<uint32_t>& csrcs() const { return csrcs_; } + const std::string& reason() const { return reason_; } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static const int kMaxNumberOfCsrcs = 0x1f - 1; // First item is sender SSRC. + + uint32_t sender_ssrc_; + std::vector<uint32_t> csrcs_; + std::string reason_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc new file mode 100644 index 0000000000..00944b3a33 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAre; +using webrtc::rtcp::Bye; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kCsrc1 = 0x22232425; +const uint32_t kCsrc2 = 0x33343536; +} // namespace + +TEST(RtcpPacketByeTest, CreateAndParseWithoutReason) { + Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + + rtc::Buffer raw = bye.Build(); + Bye parsed_bye; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye)); + + EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc()); + EXPECT_TRUE(parsed_bye.csrcs().empty()); + EXPECT_TRUE(parsed_bye.reason().empty()); +} + +TEST(RtcpPacketByeTest, CreateAndParseWithCsrcs) { + Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(bye.SetCsrcs({kCsrc1, kCsrc2})); + EXPECT_TRUE(bye.reason().empty()); + + rtc::Buffer raw = bye.Build(); + Bye parsed_bye; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye)); + + EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc()); + EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2)); + EXPECT_TRUE(parsed_bye.reason().empty()); +} + +TEST(RtcpPacketByeTest, CreateAndParseWithCsrcsAndAReason) { + Bye bye; + const std::string kReason = "Some Reason"; + + bye.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(bye.SetCsrcs({kCsrc1, kCsrc2})); + bye.SetReason(kReason); + + rtc::Buffer raw = bye.Build(); + Bye parsed_bye; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye)); + + EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc()); + EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2)); + EXPECT_EQ(kReason, parsed_bye.reason()); +} + +TEST(RtcpPacketByeTest, CreateWithTooManyCsrcs) { + Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + const int kMaxCsrcs = (1 << 5) - 2; // 5 bit len, first item is sender SSRC. + EXPECT_TRUE(bye.SetCsrcs(std::vector<uint32_t>(kMaxCsrcs, kCsrc1))); + EXPECT_FALSE(bye.SetCsrcs(std::vector<uint32_t>(kMaxCsrcs + 1, kCsrc1))); +} + +TEST(RtcpPacketByeTest, CreateAndParseWithAReason) { + Bye bye; + const std::string kReason = "Some Random Reason"; + + bye.SetSenderSsrc(kSenderSsrc); + bye.SetReason(kReason); + + rtc::Buffer raw = bye.Build(); + Bye parsed_bye; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye)); + + EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc()); + EXPECT_TRUE(parsed_bye.csrcs().empty()); + EXPECT_EQ(kReason, parsed_bye.reason()); +} + +TEST(RtcpPacketByeTest, CreateAndParseWithReasons) { + // Test that packet creation/parsing behave with reasons of different length + // both when it require padding and when it does not. + for (size_t reminder = 0; reminder < 4; ++reminder) { + const std::string kReason(4 + reminder, 'a' + reminder); + Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + bye.SetReason(kReason); + + rtc::Buffer raw = bye.Build(); + Bye parsed_bye; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye)); + + EXPECT_EQ(kReason, parsed_bye.reason()); + } +} + +TEST(RtcpPacketByeTest, ParseEmptyPacket) { + uint8_t kEmptyPacket[] = {0x80, Bye::kPacketType, 0, 0}; + Bye parsed_bye; + EXPECT_TRUE(test::ParseSinglePacket(kEmptyPacket, &parsed_bye)); + EXPECT_EQ(0u, parsed_bye.sender_ssrc()); + EXPECT_TRUE(parsed_bye.csrcs().empty()); + EXPECT_TRUE(parsed_bye.reason().empty()); +} + +TEST(RtcpPacketByeTest, ParseFailOnInvalidSrcCount) { + Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + + rtc::Buffer raw = bye.Build(); + raw[0]++; // Damage the packet: increase ssrc count by one. + + Bye parsed_bye; + EXPECT_FALSE(test::ParseSinglePacket(raw, &parsed_bye)); +} + +TEST(RtcpPacketByeTest, ParseFailOnInvalidReasonLength) { + Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + bye.SetReason("18 characters long"); + + rtc::Buffer raw = bye.Build(); + // Damage the packet: decrease payload size by 4 bytes + raw[3]--; + raw.SetSize(raw.size() - 4); + + Bye parsed_bye; + EXPECT_FALSE(test::ParseSinglePacket(raw, &parsed_bye)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.cc new file mode 100644 index 0000000000..5b54982220 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.cc @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/common_header.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr size_t CommonHeader::kHeaderSizeBytes; +// 0 1 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 |V=2|P| C/F | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 1 | Packet Type | +// ----------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 2 | length | +// --------------------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Common header for all RTCP packets, 4 octets. +bool CommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) { + const uint8_t kVersion = 2; + + if (size_bytes < kHeaderSizeBytes) { + RTC_LOG(LS_WARNING) + << "Too little data (" << size_bytes << " byte" + << (size_bytes != 1 ? "s" : "") + << ") remaining in buffer to parse RTCP header (4 bytes)."; + return false; + } + + uint8_t version = buffer[0] >> 6; + if (version != kVersion) { + RTC_LOG(LS_WARNING) << "Invalid RTCP header: Version must be " + << static_cast<int>(kVersion) << " but was " + << static_cast<int>(version); + return false; + } + + bool has_padding = (buffer[0] & 0x20) != 0; + count_or_format_ = buffer[0] & 0x1F; + packet_type_ = buffer[1]; + payload_size_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) * 4; + payload_ = buffer + kHeaderSizeBytes; + padding_size_ = 0; + + if (size_bytes < kHeaderSizeBytes + payload_size_) { + RTC_LOG(LS_WARNING) << "Buffer too small (" << size_bytes + << " bytes) to fit an RtcpPacket with a header and " + << payload_size_ << " bytes."; + return false; + } + + if (has_padding) { + if (payload_size_ == 0) { + RTC_LOG(LS_WARNING) + << "Invalid RTCP header: Padding bit set but 0 payload " + "size specified."; + return false; + } + + padding_size_ = payload_[payload_size_ - 1]; + if (padding_size_ == 0) { + RTC_LOG(LS_WARNING) + << "Invalid RTCP header: Padding bit set but 0 padding " + "size specified."; + return false; + } + if (padding_size_ > payload_size_) { + RTC_LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes (" + << padding_size_ << ") for a packet payload size of " + << payload_size_ << " bytes."; + return false; + } + payload_size_ -= padding_size_; + } + return true; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h new file mode 100644 index 0000000000..b760d169f7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_ + +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader { + public: + static constexpr size_t kHeaderSizeBytes = 4; + + CommonHeader() {} + CommonHeader(const CommonHeader&) = default; + CommonHeader& operator =(const CommonHeader&) = default; + + bool Parse(const uint8_t* buffer, size_t size_bytes); + + uint8_t type() const { return packet_type_; } + // Depending on packet type same header field can be used either as count or + // as feedback message type (fmt). Caller expected to know how it is used. + uint8_t fmt() const { return count_or_format_; } + uint8_t count() const { return count_or_format_; } + size_t payload_size_bytes() const { return payload_size_; } + const uint8_t* payload() const { return payload_; } + size_t packet_size() const { + return kHeaderSizeBytes + payload_size_ + padding_size_; + } + // Returns pointer to the next RTCP packet in compound packet. + const uint8_t* NextPacket() const { + return payload_ + payload_size_ + padding_size_; + } + + private: + uint8_t packet_type_ = 0; + uint8_t count_or_format_ = 0; + uint8_t padding_size_ = 0; + uint32_t payload_size_ = 0; + const uint8_t* payload_ = nullptr; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header_unittest.cc new file mode 100644 index 0000000000..a284642451 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header_unittest.cc @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/common_header.h" + +#include "test/gtest.h" + +using webrtc::rtcp::CommonHeader; + +namespace webrtc { + +TEST(RtcpCommonHeaderTest, TooSmallBuffer) { + uint8_t buffer[] = {0x80, 0x00, 0x00, 0x00}; + CommonHeader header; + // Buffer needs to be able to hold the header. + EXPECT_FALSE(header.Parse(buffer, 0)); + EXPECT_FALSE(header.Parse(buffer, 1)); + EXPECT_FALSE(header.Parse(buffer, 2)); + EXPECT_FALSE(header.Parse(buffer, 3)); + EXPECT_TRUE(header.Parse(buffer, 4)); +} + +TEST(RtcpCommonHeaderTest, Version) { + uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00}; + CommonHeader header; + // Version 2 is the only allowed. + buffer[0] = 0 << 6; + EXPECT_FALSE(header.Parse(buffer, sizeof(buffer))); + buffer[0] = 1 << 6; + EXPECT_FALSE(header.Parse(buffer, sizeof(buffer))); + buffer[0] = 2 << 6; + EXPECT_TRUE(header.Parse(buffer, sizeof(buffer))); + buffer[0] = 3 << 6; + EXPECT_FALSE(header.Parse(buffer, sizeof(buffer))); +} + +TEST(RtcpCommonHeaderTest, PacketSize) { + uint8_t buffer[] = {0x80, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + CommonHeader header; + EXPECT_FALSE(header.Parse(buffer, sizeof(buffer) - 1)); + EXPECT_TRUE(header.Parse(buffer, sizeof(buffer))); + EXPECT_EQ(8u, header.payload_size_bytes()); + EXPECT_EQ(buffer + sizeof(buffer), header.NextPacket()); + EXPECT_EQ(sizeof(buffer), header.packet_size()); +} + +TEST(RtcpCommonHeaderTest, PaddingAndPayloadSize) { + // Set v = 2, p = 1, but leave fmt, pt as 0. + uint8_t buffer[] = {0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + CommonHeader header; + // Padding bit set, but no byte for padding (can't specify padding length). + EXPECT_FALSE(header.Parse(buffer, 4)); + + buffer[3] = 2; // Set payload size to 2x32bit. + const size_t kPayloadSizeBytes = buffer[3] * 4; + const size_t kPaddingAddress = + CommonHeader::kHeaderSizeBytes + kPayloadSizeBytes - 1; + + // Padding one byte larger than possible. + buffer[kPaddingAddress] = kPayloadSizeBytes + 1; + EXPECT_FALSE(header.Parse(buffer, sizeof(buffer))); + + // Invalid zero padding size. + buffer[kPaddingAddress] = 0; + EXPECT_FALSE(header.Parse(buffer, sizeof(buffer))); + + // Pure padding packet. + buffer[kPaddingAddress] = kPayloadSizeBytes; + EXPECT_TRUE(header.Parse(buffer, sizeof(buffer))); + EXPECT_EQ(0u, header.payload_size_bytes()); + EXPECT_EQ(buffer + sizeof(buffer), header.NextPacket()); + EXPECT_EQ(header.payload(), buffer + CommonHeader::kHeaderSizeBytes); + EXPECT_EQ(header.packet_size(), sizeof(buffer)); + + // Single byte of actual data. + buffer[kPaddingAddress] = kPayloadSizeBytes - 1; + EXPECT_TRUE(header.Parse(buffer, sizeof(buffer))); + EXPECT_EQ(1u, header.payload_size_bytes()); + EXPECT_EQ(buffer + sizeof(buffer), header.NextPacket()); + EXPECT_EQ(header.packet_size(), sizeof(buffer)); +} + +TEST(RtcpCommonHeaderTest, FormatAndPayloadType) { + uint8_t buffer[] = {0x9e, 0xab, 0x00, 0x00}; + CommonHeader header; + EXPECT_TRUE(header.Parse(buffer, sizeof(buffer))); + + EXPECT_EQ(header.count(), 0x1e); + EXPECT_EQ(header.fmt(), 0x1e); + EXPECT_EQ(header.type(), 0xab); + EXPECT_EQ(header.payload_size_bytes(), 0u); + EXPECT_EQ(header.payload(), buffer + CommonHeader::kHeaderSizeBytes); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc new file mode 100644 index 0000000000..aec49c8ea7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/compound_packet.h" + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace rtcp { + +CompoundPacket::CompoundPacket() = default; + +CompoundPacket::~CompoundPacket() = default; + +void CompoundPacket::Append(RtcpPacket* packet) { + RTC_CHECK(packet); + appended_packets_.push_back(packet); +} + +bool CompoundPacket::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + for (RtcpPacket* appended : appended_packets_) { + if (!appended->Create(packet, index, max_length, callback)) + return false; + } + return true; +} + +size_t CompoundPacket::BlockLength() const { + size_t block_length = 0; + for (RtcpPacket* appended : appended_packets_) { + block_length += appended->BlockLength(); + } + return block_length; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h new file mode 100644 index 0000000000..a58118ea94 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/constructormagic.h" + +namespace webrtc { +namespace rtcp { + +class CompoundPacket : public RtcpPacket { + public: + CompoundPacket(); + ~CompoundPacket() override; + + void Append(RtcpPacket* packet); + + // Size of this packet in bytes (i.e. total size of nested packets). + size_t BlockLength() const override; + // Returns true if all calls to Create succeeded. + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + protected: + std::vector<RtcpPacket*> appended_packets_; + + private: + RTC_DISALLOW_COPY_AND_ASSIGN(CompoundPacket); +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc new file mode 100644 index 0000000000..156f687018 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/compound_packet.h" + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" +#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using webrtc::rtcp::Bye; +using webrtc::rtcp::CompoundPacket; +using webrtc::rtcp::Fir; +using webrtc::rtcp::ReceiverReport; +using webrtc::rtcp::ReportBlock; +using webrtc::rtcp::SenderReport; +using webrtc::test::RtcpPacketParser; + +namespace webrtc { + +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrc = 0x23456789; +const uint8_t kSeqNo = 13; + +TEST(RtcpCompoundPacketTest, AppendPacket) { + CompoundPacket compound; + Fir fir; + fir.AddRequestTo(kRemoteSsrc, kSeqNo); + ReportBlock rb; + ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(rr.AddReportBlock(rb)); + compound.Append(&rr); + compound.Append(&fir); + + rtc::Buffer packet = compound.Build(); + RtcpPacketParser parser; + parser.Parse(packet.data(), packet.size()); + EXPECT_EQ(1, parser.receiver_report()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser.receiver_report()->sender_ssrc()); + EXPECT_EQ(1u, parser.receiver_report()->report_blocks().size()); + EXPECT_EQ(1, parser.fir()->num_packets()); +} + +TEST(RtcpCompoundPacketTest, AppendPacketWithOwnAppendedPacket) { + CompoundPacket root; + CompoundPacket leaf; + Fir fir; + fir.AddRequestTo(kRemoteSsrc, kSeqNo); + Bye bye; + ReportBlock rb; + + ReceiverReport rr; + EXPECT_TRUE(rr.AddReportBlock(rb)); + leaf.Append(&rr); + leaf.Append(&fir); + + SenderReport sr; + root.Append(&sr); + root.Append(&bye); + root.Append(&leaf); + + rtc::Buffer packet = root.Build(); + RtcpPacketParser parser; + parser.Parse(packet.data(), packet.size()); + EXPECT_EQ(1, parser.sender_report()->num_packets()); + EXPECT_EQ(1, parser.receiver_report()->num_packets()); + EXPECT_EQ(1u, parser.receiver_report()->report_blocks().size()); + EXPECT_EQ(1, parser.bye()->num_packets()); + EXPECT_EQ(1, parser.fir()->num_packets()); +} + +TEST(RtcpCompoundPacketTest, BuildWithInputBuffer) { + CompoundPacket compound; + Fir fir; + fir.AddRequestTo(kRemoteSsrc, kSeqNo); + ReportBlock rb; + ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(rr.AddReportBlock(rb)); + compound.Append(&rr); + compound.Append(&fir); + + const size_t kRrLength = 8; + const size_t kReportBlockLength = 24; + const size_t kFirLength = 20; + + class Verifier : public rtcp::RtcpPacket::PacketReadyCallback { + public: + void OnPacketReady(uint8_t* data, size_t length) override { + RtcpPacketParser parser; + parser.Parse(data, length); + EXPECT_EQ(1, parser.receiver_report()->num_packets()); + EXPECT_EQ(1u, parser.receiver_report()->report_blocks().size()); + EXPECT_EQ(1, parser.fir()->num_packets()); + ++packets_created_; + } + + int packets_created_ = 0; + } verifier; + const size_t kBufferSize = kRrLength + kReportBlockLength + kFirLength; + uint8_t buffer[kBufferSize]; + EXPECT_TRUE(compound.BuildExternalBuffer(buffer, kBufferSize, &verifier)); + EXPECT_EQ(1, verifier.packets_created_); +} + +TEST(RtcpCompoundPacketTest, BuildWithTooSmallBuffer_FragmentedSend) { + CompoundPacket compound; + Fir fir; + fir.AddRequestTo(kRemoteSsrc, kSeqNo); + ReportBlock rb; + ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(rr.AddReportBlock(rb)); + compound.Append(&rr); + compound.Append(&fir); + + const size_t kRrLength = 8; + const size_t kReportBlockLength = 24; + + class Verifier : public rtcp::RtcpPacket::PacketReadyCallback { + public: + void OnPacketReady(uint8_t* data, size_t length) override { + RtcpPacketParser parser; + parser.Parse(data, length); + switch (packets_created_++) { + case 0: + EXPECT_EQ(1, parser.receiver_report()->num_packets()); + EXPECT_EQ(1U, parser.receiver_report()->report_blocks().size()); + EXPECT_EQ(0, parser.fir()->num_packets()); + break; + case 1: + EXPECT_EQ(0, parser.receiver_report()->num_packets()); + EXPECT_EQ(0U, parser.receiver_report()->report_blocks().size()); + EXPECT_EQ(1, parser.fir()->num_packets()); + break; + default: + ADD_FAILURE() << "OnPacketReady not expected to be called " + << packets_created_ << " times."; + } + } + + int packets_created_ = 0; + } verifier; + const size_t kBufferSize = kRrLength + kReportBlockLength; + uint8_t buffer[kBufferSize]; + EXPECT_TRUE(compound.BuildExternalBuffer(buffer, kBufferSize, &verifier)); + EXPECT_EQ(2, verifier.packets_created_); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc new file mode 100644 index 0000000000..6863def2fe --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { +namespace rtcp { +// DLRR Report Block (RFC 3611). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | BT=5 | reserved | block length | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_1 (SSRC of first receiver) | sub- +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// | last RR (LRR) | 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | delay since last RR (DLRR) | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_2 (SSRC of second receiver) | sub- +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// : ... : 2 + +Dlrr::Dlrr() = default; + +Dlrr::Dlrr(const Dlrr& other) = default; + +Dlrr::~Dlrr() = default; + +bool Dlrr::Parse(const uint8_t* buffer, uint16_t block_length_32bits) { + RTC_DCHECK(buffer[0] == kBlockType); + // kReserved = buffer[1]; + RTC_DCHECK_EQ(block_length_32bits, + ByteReader<uint16_t>::ReadBigEndian(&buffer[2])); + if (block_length_32bits % 3 != 0) { + RTC_LOG(LS_WARNING) << "Invalid size for dlrr block."; + return false; + } + + size_t blocks_count = block_length_32bits / 3; + const uint8_t* read_at = buffer + kBlockHeaderLength; + sub_blocks_.resize(blocks_count); + for (ReceiveTimeInfo& sub_block : sub_blocks_) { + sub_block.ssrc = ByteReader<uint32_t>::ReadBigEndian(&read_at[0]); + sub_block.last_rr = ByteReader<uint32_t>::ReadBigEndian(&read_at[4]); + sub_block.delay_since_last_rr = + ByteReader<uint32_t>::ReadBigEndian(&read_at[8]); + read_at += kSubBlockLength; + } + return true; +} + +size_t Dlrr::BlockLength() const { + if (sub_blocks_.empty()) + return 0; + return kBlockHeaderLength + kSubBlockLength * sub_blocks_.size(); +} + +void Dlrr::Create(uint8_t* buffer) const { + if (sub_blocks_.empty()) // No subblocks, no need to write header either. + return; + // Create block header. + const uint8_t kReserved = 0; + buffer[0] = kBlockType; + buffer[1] = kReserved; + ByteWriter<uint16_t>::WriteBigEndian( + &buffer[2], rtc::dchecked_cast<uint16_t>(3 * sub_blocks_.size())); + // Create sub blocks. + uint8_t* write_at = buffer + kBlockHeaderLength; + for (const ReceiveTimeInfo& sub_block : sub_blocks_) { + ByteWriter<uint32_t>::WriteBigEndian(&write_at[0], sub_block.ssrc); + ByteWriter<uint32_t>::WriteBigEndian(&write_at[4], sub_block.last_rr); + ByteWriter<uint32_t>::WriteBigEndian(&write_at[8], + sub_block.delay_since_last_rr); + write_at += kSubBlockLength; + } + RTC_DCHECK_EQ(buffer + BlockLength(), write_at); +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h new file mode 100644 index 0000000000..f0f23022f5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h @@ -0,0 +1,69 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_ + +#include <vector> + +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +struct ReceiveTimeInfo { + // RFC 3611 4.5 + ReceiveTimeInfo() : ssrc(0), last_rr(0), delay_since_last_rr(0) {} + ReceiveTimeInfo(uint32_t ssrc, uint32_t last_rr, uint32_t delay) + : ssrc(ssrc), last_rr(last_rr), delay_since_last_rr(delay) {} + uint32_t ssrc; + uint32_t last_rr; + uint32_t delay_since_last_rr; +}; + +// DLRR Report Block: Delay since the Last Receiver Report (RFC 3611). +class Dlrr { + public: + static const uint8_t kBlockType = 5; + + Dlrr(); + Dlrr(const Dlrr& other); + ~Dlrr(); + + Dlrr& operator=(const Dlrr& other) = default; + + // Dlrr without items treated same as no dlrr block. + explicit operator bool() const { return !sub_blocks_.empty(); } + + // Second parameter is value read from block header, + // i.e. size of block in 32bits excluding block header itself. + bool Parse(const uint8_t* buffer, uint16_t block_length_32bits); + + size_t BlockLength() const; + // Fills buffer with the Dlrr. + // Consumes BlockLength() bytes. + void Create(uint8_t* buffer) const; + + void ClearItems() { sub_blocks_.clear(); } + void AddDlrrItem(const ReceiveTimeInfo& time_info) { + sub_blocks_.push_back(time_info); + } + + const std::vector<ReceiveTimeInfo>& sub_blocks() const { return sub_blocks_; } + + private: + static const size_t kBlockHeaderLength = 4; + static const size_t kSubBlockLength = 12; + + std::vector<ReceiveTimeInfo> sub_blocks_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc new file mode 100644 index 0000000000..408d0011b8 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "test/gtest.h" + +using webrtc::rtcp::Dlrr; +using webrtc::rtcp::ReceiveTimeInfo; + +namespace webrtc { +namespace { +const uint32_t kSsrc = 0x12345678; +const uint32_t kLastRR = 0x23344556; +const uint32_t kDelay = 0x33343536; +const uint8_t kBlock[] = {0x05, 0x00, 0x00, 0x03, 0x12, 0x34, 0x56, 0x78, + 0x23, 0x34, 0x45, 0x56, 0x33, 0x34, 0x35, 0x36}; +const size_t kBlockSizeBytes = sizeof(kBlock); +} // namespace + +TEST(RtcpPacketDlrrTest, Empty) { + Dlrr dlrr; + + EXPECT_EQ(0u, dlrr.BlockLength()); +} + +TEST(RtcpPacketDlrrTest, Create) { + Dlrr dlrr; + dlrr.AddDlrrItem(ReceiveTimeInfo(kSsrc, kLastRR, kDelay)); + + ASSERT_EQ(kBlockSizeBytes, dlrr.BlockLength()); + uint8_t buffer[kBlockSizeBytes]; + + dlrr.Create(buffer); + EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes)); +} + +TEST(RtcpPacketDlrrTest, Parse) { + Dlrr dlrr; + uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&kBlock[2]); + EXPECT_TRUE(dlrr.Parse(kBlock, block_length)); + + EXPECT_EQ(1u, dlrr.sub_blocks().size()); + const ReceiveTimeInfo& block = dlrr.sub_blocks().front(); + EXPECT_EQ(kSsrc, block.ssrc); + EXPECT_EQ(kLastRR, block.last_rr); + EXPECT_EQ(kDelay, block.delay_since_last_rr); +} + +TEST(RtcpPacketDlrrTest, ParseFailsOnBadSize) { + const size_t kBigBufferSize = 0x100; // More than enough. + uint8_t buffer[kBigBufferSize]; + buffer[0] = Dlrr::kBlockType; + buffer[1] = 0; // Reserved. + buffer[2] = 0; // Most significant size byte. + for (uint8_t size = 3; size < 6; ++size) { + buffer[3] = size; + Dlrr dlrr; + // Parse should be successful only when size is multiple of 3. + EXPECT_EQ(size % 3 == 0, dlrr.Parse(buffer, static_cast<uint16_t>(size))); + } +} + +TEST(RtcpPacketDlrrTest, CreateAndParseManySubBlocks) { + const size_t kBufferSize = 0x1000; // More than enough. + const size_t kManyDlrrItems = 50; + uint8_t buffer[kBufferSize]; + + // Create. + Dlrr dlrr; + for (size_t i = 1; i <= kManyDlrrItems; ++i) + dlrr.AddDlrrItem(ReceiveTimeInfo(kSsrc + i, kLastRR + i, kDelay + i)); + size_t used_buffer_size = dlrr.BlockLength(); + ASSERT_LE(used_buffer_size, kBufferSize); + dlrr.Create(buffer); + + // Parse. + Dlrr parsed; + uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]); + EXPECT_EQ(used_buffer_size, (block_length + 1) * 4u); + EXPECT_TRUE(parsed.Parse(buffer, block_length)); + EXPECT_EQ(kManyDlrrItems, parsed.sub_blocks().size()); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc new file mode 100644 index 0000000000..a511289727 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t ExtendedJitterReport::kPacketType; +// Transmission Time Offsets in RTP Streams (RFC 5450). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// hdr |V=2|P| RC | PT=IJ=195 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | inter-arrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// . . +// . . +// . . +// | inter-arrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// If present, this RTCP packet must be placed after a receiver report +// (inside a compound RTCP packet), and MUST have the same value for RC +// (reception report count) as the receiver report. + +ExtendedJitterReport::ExtendedJitterReport() = default; + +ExtendedJitterReport::~ExtendedJitterReport() = default; + +bool ExtendedJitterReport::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + + const uint8_t number_of_jitters = packet.count(); + + if (packet.payload_size_bytes() < number_of_jitters * kJitterSizeBytes) { + RTC_LOG(LS_WARNING) << "Packet is too small to contain all the jitter."; + return false; + } + + inter_arrival_jitters_.resize(number_of_jitters); + for (size_t index = 0; index < number_of_jitters; ++index) { + inter_arrival_jitters_[index] = ByteReader<uint32_t>::ReadBigEndian( + &packet.payload()[index * kJitterSizeBytes]); + } + + return true; +} + +bool ExtendedJitterReport::SetJitterValues(std::vector<uint32_t> values) { + if (values.size() > kMaxNumberOfJitterValues) { + RTC_LOG(LS_WARNING) << "Too many inter-arrival jitter items."; + return false; + } + inter_arrival_jitters_ = std::move(values); + return true; +} + +size_t ExtendedJitterReport::BlockLength() const { + return kHeaderLength + kJitterSizeBytes * inter_arrival_jitters_.size(); +} + +bool ExtendedJitterReport::Create( + uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + size_t length = inter_arrival_jitters_.size(); + CreateHeader(length, kPacketType, length, packet, index); + + for (uint32_t jitter : inter_arrival_jitters_) { + ByteWriter<uint32_t>::WriteBigEndian(packet + *index, jitter); + *index += kJitterSizeBytes; + } + // Sanity check. + RTC_DCHECK_EQ(index_end, *index); + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h new file mode 100644 index 0000000000..a40cfee2b3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h @@ -0,0 +1,54 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +class ExtendedJitterReport : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 195; + static constexpr size_t kMaxNumberOfJitterValues = 0x1f; + + ExtendedJitterReport(); + ~ExtendedJitterReport() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + bool SetJitterValues(std::vector<uint32_t> jitter_values); + + const std::vector<uint32_t>& jitter_values() { + return inter_arrival_jitters_; + } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static constexpr size_t kJitterSizeBytes = 4; + + std::vector<uint32_t> inter_arrival_jitters_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc new file mode 100644 index 0000000000..7598fefed1 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAre; +using testing::IsEmpty; +using webrtc::rtcp::ExtendedJitterReport; + +namespace webrtc { +namespace { +constexpr uint32_t kJitter1 = 0x11121314; +constexpr uint32_t kJitter2 = 0x22242628; +} // namespace + +TEST(RtcpPacketExtendedJitterReportTest, CreateAndParseWithoutItems) { + ExtendedJitterReport ij; + rtc::Buffer raw = ij.Build(); + + ExtendedJitterReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed)); + + EXPECT_THAT(parsed.jitter_values(), IsEmpty()); +} + +TEST(RtcpPacketExtendedJitterReportTest, CreateAndParseWithOneItem) { + ExtendedJitterReport ij; + EXPECT_TRUE(ij.SetJitterValues({kJitter1})); + rtc::Buffer raw = ij.Build(); + + ExtendedJitterReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed)); + + EXPECT_THAT(parsed.jitter_values(), ElementsAre(kJitter1)); +} + +TEST(RtcpPacketExtendedJitterReportTest, CreateAndParseWithTwoItems) { + ExtendedJitterReport ij; + EXPECT_TRUE(ij.SetJitterValues({kJitter1, kJitter2})); + rtc::Buffer raw = ij.Build(); + + ExtendedJitterReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed)); + + EXPECT_THAT(parsed.jitter_values(), ElementsAre(kJitter1, kJitter2)); +} + +TEST(RtcpPacketExtendedJitterReportTest, CreateWithTooManyItems) { + ExtendedJitterReport ij; + const int kMaxItems = ExtendedJitterReport::kMaxNumberOfJitterValues; + EXPECT_FALSE( + ij.SetJitterValues(std::vector<uint32_t>(kMaxItems + 1, kJitter1))); + EXPECT_TRUE(ij.SetJitterValues(std::vector<uint32_t>(kMaxItems, kJitter1))); +} + +TEST(RtcpPacketExtendedJitterReportTest, ParseFailsWithTooManyItems) { + ExtendedJitterReport ij; + ij.SetJitterValues({kJitter1}); + rtc::Buffer raw = ij.Build(); + raw[0]++; // Damage packet: increase jitter count by 1. + ExtendedJitterReport parsed; + EXPECT_FALSE(test::ParseSinglePacket(raw, &parsed)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc new file mode 100644 index 0000000000..066f2026e5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/extended_reports.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t ExtendedReports::kPacketType; +// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR). +// +// Format for XR packets: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P|reserved | PT=XR=207 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : report blocks : +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Extended report block: +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Block Type | reserved | block length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : type-specific block contents : +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +ExtendedReports::ExtendedReports() : sender_ssrc_(0) {} +ExtendedReports::~ExtendedReports() {} + +bool ExtendedReports::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + + if (packet.payload_size_bytes() < kXrBaseLength) { + RTC_LOG(LS_WARNING) + << "Packet is too small to be an ExtendedReports packet."; + return false; + } + + sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(packet.payload()); + rrtr_block_.reset(); + dlrr_block_.ClearItems(); + voip_metric_block_.reset(); + target_bitrate_ = rtc::nullopt; + + const uint8_t* current_block = packet.payload() + kXrBaseLength; + const uint8_t* const packet_end = + packet.payload() + packet.payload_size_bytes(); + constexpr size_t kBlockHeaderSizeBytes = 4; + while (current_block + kBlockHeaderSizeBytes <= packet_end) { + uint8_t block_type = ByteReader<uint8_t>::ReadBigEndian(current_block); + uint16_t block_length = + ByteReader<uint16_t>::ReadBigEndian(current_block + 2); + const uint8_t* next_block = + current_block + kBlockHeaderSizeBytes + block_length * 4; + if (next_block > packet_end) { + RTC_LOG(LS_WARNING) + << "Report block in extended report packet is too big."; + return false; + } + switch (block_type) { + case Rrtr::kBlockType: + ParseRrtrBlock(current_block, block_length); + break; + case Dlrr::kBlockType: + ParseDlrrBlock(current_block, block_length); + break; + case VoipMetric::kBlockType: + ParseVoipMetricBlock(current_block, block_length); + break; + case TargetBitrate::kBlockType: + ParseTargetBitrateBlock(current_block, block_length); + break; + default: + // Unknown block, ignore. + RTC_LOG(LS_WARNING) + << "Unknown extended report block type " << block_type; + break; + } + current_block = next_block; + } + + return true; +} + +void ExtendedReports::SetRrtr(const Rrtr& rrtr) { + if (rrtr_block_) + RTC_LOG(LS_WARNING) << "Rrtr already set, overwriting."; + rrtr_block_.emplace(rrtr); +} + +void ExtendedReports::AddDlrrItem(const ReceiveTimeInfo& time_info) { + dlrr_block_.AddDlrrItem(time_info); +} + +void ExtendedReports::SetVoipMetric(const VoipMetric& voip_metric) { + if (voip_metric_block_) + RTC_LOG(LS_WARNING) << "Voip metric already set, overwriting."; + voip_metric_block_.emplace(voip_metric); +} + +void ExtendedReports::SetTargetBitrate(const TargetBitrate& bitrate) { + if (target_bitrate_) + RTC_LOG(LS_WARNING) << "TargetBitrate already set, overwriting."; + + target_bitrate_ = bitrate; +} + +size_t ExtendedReports::BlockLength() const { + return kHeaderLength + kXrBaseLength + RrtrLength() + DlrrLength() + + VoipMetricLength() + TargetBitrateLength(); +} + +bool ExtendedReports::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + size_t index_end = *index + BlockLength(); + const uint8_t kReserved = 0; + CreateHeader(kReserved, kPacketType, HeaderLength(), packet, index); + ByteWriter<uint32_t>::WriteBigEndian(packet + *index, sender_ssrc_); + *index += sizeof(uint32_t); + if (rrtr_block_) { + rrtr_block_->Create(packet + *index); + *index += Rrtr::kLength; + } + if (dlrr_block_) { + dlrr_block_.Create(packet + *index); + *index += dlrr_block_.BlockLength(); + } + if (voip_metric_block_) { + voip_metric_block_->Create(packet + *index); + *index += VoipMetric::kLength; + } + if (target_bitrate_) { + target_bitrate_->Create(packet + *index); + *index += target_bitrate_->BlockLength(); + } + RTC_CHECK_EQ(*index, index_end); + return true; +} + +size_t ExtendedReports::TargetBitrateLength() const { + if (target_bitrate_) + return target_bitrate_->BlockLength(); + return 0; +} + +void ExtendedReports::ParseRrtrBlock(const uint8_t* block, + uint16_t block_length) { + if (block_length != Rrtr::kBlockLength) { + RTC_LOG(LS_WARNING) << "Incorrect rrtr block size " << block_length + << " Should be " << Rrtr::kBlockLength; + return; + } + if (rrtr_block_) { + RTC_LOG(LS_WARNING) + << "Two rrtr blocks found in same Extended Report packet"; + return; + } + rrtr_block_.emplace(); + rrtr_block_->Parse(block); +} + +void ExtendedReports::ParseDlrrBlock(const uint8_t* block, + uint16_t block_length) { + if (dlrr_block_) { + RTC_LOG(LS_WARNING) + << "Two Dlrr blocks found in same Extended Report packet"; + return; + } + dlrr_block_.Parse(block, block_length); +} + +void ExtendedReports::ParseVoipMetricBlock(const uint8_t* block, + uint16_t block_length) { + if (block_length != VoipMetric::kBlockLength) { + RTC_LOG(LS_WARNING) << "Incorrect voip metric block size " << block_length + << " Should be " << VoipMetric::kBlockLength; + return; + } + if (voip_metric_block_) { + RTC_LOG(LS_WARNING) + << "Two Voip Metric blocks found in same Extended Report packet"; + return; + } + voip_metric_block_.emplace(); + voip_metric_block_->Parse(block); +} + +void ExtendedReports::ParseTargetBitrateBlock(const uint8_t* block, + uint16_t block_length) { + target_bitrate_.emplace(); + target_bitrate_->Parse(block, block_length); +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h new file mode 100644 index 0000000000..2fe5618867 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_ + +#include <vector> + +#include "api/optional.h" +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" +#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h" +#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h" +#include "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR). +class ExtendedReports : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 207; + + ExtendedReports(); + ~ExtendedReports() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; } + + void SetRrtr(const Rrtr& rrtr); + void AddDlrrItem(const ReceiveTimeInfo& time_info); + void SetVoipMetric(const VoipMetric& voip_metric); + void SetTargetBitrate(const TargetBitrate& target_bitrate); + + uint32_t sender_ssrc() const { return sender_ssrc_; } + const rtc::Optional<Rrtr>& rrtr() const { return rrtr_block_; } + const Dlrr& dlrr() const { return dlrr_block_; } + const rtc::Optional<VoipMetric>& voip_metric() const { + return voip_metric_block_; + } + const rtc::Optional<TargetBitrate>& target_bitrate() const { + return target_bitrate_; + } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static constexpr size_t kXrBaseLength = 4; + + size_t RrtrLength() const { return rrtr_block_ ? Rrtr::kLength : 0; } + size_t DlrrLength() const { return dlrr_block_.BlockLength(); } + size_t VoipMetricLength() const { + return voip_metric_block_ ? VoipMetric::kLength : 0; + } + size_t TargetBitrateLength() const; + + void ParseRrtrBlock(const uint8_t* block, uint16_t block_length); + void ParseDlrrBlock(const uint8_t* block, uint16_t block_length); + void ParseVoipMetricBlock(const uint8_t* block, uint16_t block_length); + void ParseTargetBitrateBlock(const uint8_t* block, uint16_t block_length); + + uint32_t sender_ssrc_; + rtc::Optional<Rrtr> rrtr_block_; + Dlrr dlrr_block_; // Dlrr without items treated same as no dlrr block. + rtc::Optional<VoipMetric> voip_metric_block_; + rtc::Optional<TargetBitrate> target_bitrate_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc new file mode 100644 index 0000000000..088b363c54 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/extended_reports.h" + +#include "rtc_base/random.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAre; +using testing::ElementsAreArray; +using testing::make_tuple; +using webrtc::rtcp::Dlrr; +using webrtc::rtcp::ExtendedReports; +using webrtc::rtcp::ReceiveTimeInfo; +using webrtc::rtcp::Rrtr; +using webrtc::rtcp::VoipMetric; + +namespace webrtc { +// Define comparision operators that shouldn't be needed in production, +// but make testing matches more clear. +bool operator==(const RTCPVoIPMetric& metric1, const RTCPVoIPMetric& metric2) { + return metric1.lossRate == metric2.lossRate && + metric1.discardRate == metric2.discardRate && + metric1.burstDensity == metric2.burstDensity && + metric1.gapDensity == metric2.gapDensity && + metric1.burstDuration == metric2.burstDuration && + metric1.gapDuration == metric2.gapDuration && + metric1.roundTripDelay == metric2.roundTripDelay && + metric1.endSystemDelay == metric2.endSystemDelay && + metric1.signalLevel == metric2.signalLevel && + metric1.noiseLevel == metric2.noiseLevel && + metric1.RERL == metric2.RERL && + metric1.Gmin == metric2.Gmin && + metric1.Rfactor == metric2.Rfactor && + metric1.extRfactor == metric2.extRfactor && + metric1.MOSLQ == metric2.MOSLQ && + metric1.MOSCQ == metric2.MOSCQ && + metric1.RXconfig == metric2.RXconfig && + metric1.JBnominal == metric2.JBnominal && + metric1.JBmax == metric2.JBmax && + metric1.JBabsMax == metric2.JBabsMax; +} + +namespace rtcp { +bool operator==(const Rrtr& rrtr1, const Rrtr& rrtr2) { + return rrtr1.ntp() == rrtr2.ntp(); +} + +bool operator==(const ReceiveTimeInfo& time1, const ReceiveTimeInfo& time2) { + return time1.ssrc == time2.ssrc && + time1.last_rr == time2.last_rr && + time1.delay_since_last_rr == time2.delay_since_last_rr; +} + +bool operator==(const VoipMetric& metric1, const VoipMetric& metric2) { + return metric1.ssrc() == metric2.ssrc() && + metric1.voip_metric() == metric2.voip_metric(); +} +} // namespace rtcp + +namespace { +constexpr uint32_t kSenderSsrc = 0x12345678; +constexpr uint8_t kEmptyPacket[] = {0x80, 207, 0x00, 0x01, + 0x12, 0x34, 0x56, 0x78}; +} // namespace + +class RtcpPacketExtendedReportsTest : public ::testing::Test { + public: + RtcpPacketExtendedReportsTest() : random_(0x123456789) {} + + protected: + template <typename T> + T Rand() { + return random_.Rand<T>(); + } + + private: + Random random_; +}; + +template <> +ReceiveTimeInfo RtcpPacketExtendedReportsTest::Rand<ReceiveTimeInfo>() { + uint32_t ssrc = Rand<uint32_t>(); + uint32_t last_rr = Rand<uint32_t>(); + uint32_t delay_since_last_rr = Rand<uint32_t>(); + return ReceiveTimeInfo(ssrc, last_rr, delay_since_last_rr); +} + +template <> +NtpTime RtcpPacketExtendedReportsTest::Rand<NtpTime>() { + uint32_t secs = Rand<uint32_t>(); + uint32_t frac = Rand<uint32_t>(); + return NtpTime(secs, frac); +} + +template <> +Rrtr RtcpPacketExtendedReportsTest::Rand<Rrtr>() { + Rrtr rrtr; + rrtr.SetNtp(Rand<NtpTime>()); + return rrtr; +} + +template <> +RTCPVoIPMetric RtcpPacketExtendedReportsTest::Rand<RTCPVoIPMetric>() { + RTCPVoIPMetric metric; + metric.lossRate = Rand<uint8_t>(); + metric.discardRate = Rand<uint8_t>(); + metric.burstDensity = Rand<uint8_t>(); + metric.gapDensity = Rand<uint8_t>(); + metric.burstDuration = Rand<uint16_t>(); + metric.gapDuration = Rand<uint16_t>(); + metric.roundTripDelay = Rand<uint16_t>(); + metric.endSystemDelay = Rand<uint16_t>(); + metric.signalLevel = Rand<uint8_t>(); + metric.noiseLevel = Rand<uint8_t>(); + metric.RERL = Rand<uint8_t>(); + metric.Gmin = Rand<uint8_t>(); + metric.Rfactor = Rand<uint8_t>(); + metric.extRfactor = Rand<uint8_t>(); + metric.MOSLQ = Rand<uint8_t>(); + metric.MOSCQ = Rand<uint8_t>(); + metric.RXconfig = Rand<uint8_t>(); + metric.JBnominal = Rand<uint16_t>(); + metric.JBmax = Rand<uint16_t>(); + metric.JBabsMax = Rand<uint16_t>(); + return metric; +} + +template <> +VoipMetric RtcpPacketExtendedReportsTest::Rand<VoipMetric>() { + VoipMetric voip_metric; + voip_metric.SetMediaSsrc(Rand<uint32_t>()); + voip_metric.SetVoipMetric(Rand<RTCPVoIPMetric>()); + return voip_metric; +} + +TEST_F(RtcpPacketExtendedReportsTest, CreateWithoutReportBlocks) { + ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + + rtc::Buffer packet = xr.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kEmptyPacket)); +} + +TEST_F(RtcpPacketExtendedReportsTest, ParseWithoutReportBlocks) { + ExtendedReports parsed; + EXPECT_TRUE(test::ParseSinglePacket(kEmptyPacket, &parsed)); + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_FALSE(parsed.rrtr()); + EXPECT_FALSE(parsed.dlrr()); + EXPECT_FALSE(parsed.voip_metric()); +} + +TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithRrtrBlock) { + const Rrtr kRrtr = Rand<Rrtr>(); + ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetRrtr(kRrtr); + rtc::Buffer packet = xr.Build(); + + ExtendedReports mparsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed)); + const ExtendedReports& parsed = mparsed; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kRrtr, parsed.rrtr()); +} + +TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithDlrrWithOneSubBlock) { + const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>(); + ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(kTimeInfo); + + rtc::Buffer packet = xr.Build(); + + ExtendedReports mparsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed)); + const ExtendedReports& parsed = mparsed; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo)); +} + +TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithDlrrWithTwoSubBlocks) { + const ReceiveTimeInfo kTimeInfo1 = Rand<ReceiveTimeInfo>(); + const ReceiveTimeInfo kTimeInfo2 = Rand<ReceiveTimeInfo>(); + ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(kTimeInfo1); + xr.AddDlrrItem(kTimeInfo2); + + rtc::Buffer packet = xr.Build(); + + ExtendedReports mparsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed)); + const ExtendedReports& parsed = mparsed; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo1, kTimeInfo2)); +} + +TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithVoipMetric) { + const VoipMetric kVoipMetric = Rand<VoipMetric>(); + + ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetVoipMetric(kVoipMetric); + + rtc::Buffer packet = xr.Build(); + + ExtendedReports mparsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed)); + const ExtendedReports& parsed = mparsed; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kVoipMetric, parsed.voip_metric()); +} + +TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMultipleReportBlocks) { + const Rrtr kRrtr = Rand<Rrtr>(); + const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>(); + const VoipMetric kVoipMetric = Rand<VoipMetric>(); + + ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetRrtr(kRrtr); + xr.AddDlrrItem(kTimeInfo); + xr.SetVoipMetric(kVoipMetric); + + rtc::Buffer packet = xr.Build(); + + ExtendedReports mparsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed)); + const ExtendedReports& parsed = mparsed; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kRrtr, parsed.rrtr()); + EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo)); + EXPECT_EQ(kVoipMetric, parsed.voip_metric()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.cc new file mode 100644 index 0000000000..a7692fbfff --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.cc @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/fir.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Fir::kFeedbackMessageType; +// RFC 4585: Feedback format. +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of media source (unused) = 0 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : Feedback Control Information (FCI) : +// : : +// Full intra request (FIR) (RFC 5104). +// The Feedback Control Information (FCI) for the Full Intra Request +// consists of one or more FCI entries. +// FCI: +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Seq nr. | Reserved = 0 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Fir::Fir() = default; + +Fir::~Fir() = default; + +bool Fir::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + + // The FCI field MUST contain one or more FIR entries. + if (packet.payload_size_bytes() < kCommonFeedbackLength + kFciLength) { + RTC_LOG(LS_WARNING) << "Packet is too small to be a valid FIR packet."; + return false; + } + + if ((packet.payload_size_bytes() - kCommonFeedbackLength) % kFciLength != 0) { + RTC_LOG(LS_WARNING) << "Invalid size for a valid FIR packet."; + return false; + } + + ParseCommonFeedback(packet.payload()); + + size_t number_of_fci_items = + (packet.payload_size_bytes() - kCommonFeedbackLength) / kFciLength; + const uint8_t* next_fci = packet.payload() + kCommonFeedbackLength; + items_.resize(number_of_fci_items); + for (Request& request : items_) { + request.ssrc = ByteReader<uint32_t>::ReadBigEndian(next_fci); + request.seq_nr = ByteReader<uint8_t>::ReadBigEndian(next_fci + 4); + next_fci += kFciLength; + } + return true; +} + +size_t Fir::BlockLength() const { + return kHeaderLength + kCommonFeedbackLength + kFciLength * items_.size(); +} + +bool Fir::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + RTC_DCHECK(!items_.empty()); + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + size_t index_end = *index + BlockLength(); + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, + index); + RTC_DCHECK_EQ(Psfb::media_ssrc(), 0); + CreateCommonFeedback(packet + *index); + *index += kCommonFeedbackLength; + + constexpr uint32_t kReserved = 0; + for (const Request& request : items_) { + ByteWriter<uint32_t>::WriteBigEndian(packet + *index, request.ssrc); + ByteWriter<uint8_t>::WriteBigEndian(packet + *index + 4, request.seq_nr); + ByteWriter<uint32_t, 3>::WriteBigEndian(packet + *index + 5, kReserved); + *index += kFciLength; + } + RTC_CHECK_EQ(*index, index_end); + return true; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.h new file mode 100644 index 0000000000..80bf5c6359 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_FIR_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_FIR_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; +// Full intra request (FIR) (RFC 5104). +class Fir : public Psfb { + public: + static constexpr uint8_t kFeedbackMessageType = 4; + struct Request { + Request() : ssrc(0), seq_nr(0) {} + Request(uint32_t ssrc, uint8_t seq_nr) : ssrc(ssrc), seq_nr(seq_nr) {} + uint32_t ssrc; + uint8_t seq_nr; + }; + + Fir(); + ~Fir() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void AddRequestTo(uint32_t ssrc, uint8_t seq_num) { + items_.emplace_back(ssrc, seq_num); + } + const std::vector<Request>& requests() const { return items_; } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static constexpr size_t kFciLength = 8; + + // SSRC of media source is not used in FIR packet. Shadow base functions. + void SetMediaSsrc(uint32_t ssrc); + uint32_t media_ssrc() const; + + std::vector<Request> items_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_FIR_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir_unittest.cc new file mode 100644 index 0000000000..2800fbc79e --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir_unittest.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/fir.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::AllOf; +using testing::ElementsAre; +using testing::ElementsAreArray; +using testing::Eq; +using testing::Field; +using testing::make_tuple; +using webrtc::rtcp::Fir; + +namespace webrtc { +namespace { + +constexpr uint32_t kSenderSsrc = 0x12345678; +constexpr uint32_t kRemoteSsrc = 0x23456789; +constexpr uint8_t kSeqNr = 13; +// Manually created Fir packet matching constants above. +constexpr uint8_t kPacket[] = {0x84, 206, 0x00, 0x04, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, + 0x23, 0x45, 0x67, 0x89, + 0x0d, 0x00, 0x00, 0x00}; +} // namespace + +TEST(RtcpPacketFirTest, Parse) { + Fir mutable_parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &mutable_parsed)); + const Fir& parsed = mutable_parsed; // Read values from constant object. + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_THAT(parsed.requests(), + ElementsAre(AllOf(Field(&Fir::Request::ssrc, Eq(kRemoteSsrc)), + Field(&Fir::Request::seq_nr, Eq(kSeqNr))))); +} + +TEST(RtcpPacketFirTest, Create) { + Fir fir; + fir.SetSenderSsrc(kSenderSsrc); + fir.AddRequestTo(kRemoteSsrc, kSeqNr); + + rtc::Buffer packet = fir.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketFirTest, TwoFciEntries) { + Fir fir; + fir.SetSenderSsrc(kSenderSsrc); + fir.AddRequestTo(kRemoteSsrc, kSeqNr); + fir.AddRequestTo(kRemoteSsrc + 1, kSeqNr + 1); + + rtc::Buffer packet = fir.Build(); + Fir parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_THAT(parsed.requests(), + ElementsAre(AllOf(Field(&Fir::Request::ssrc, Eq(kRemoteSsrc)), + Field(&Fir::Request::seq_nr, Eq(kSeqNr))), + AllOf(Field(&Fir::Request::ssrc, Eq(kRemoteSsrc + 1)), + Field(&Fir::Request::seq_nr, Eq(kSeqNr + 1))))); +} + +TEST(RtcpPacketFirTest, ParseFailsOnZeroFciEntries) { + constexpr uint8_t kPacketWithoutFci[] = {0x84, 206, 0x00, 0x02, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00}; + Fir parsed; + EXPECT_FALSE(test::ParseSinglePacket(kPacketWithoutFci, &parsed)); +} + +TEST(RtcpPacketFirTest, ParseFailsOnFractionalFciEntries) { + constexpr uint8_t kPacketWithOneAndHalfFci[] = {0x84, 206, 0x00, 0x05, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, + 0x23, 0x45, 0x67, 0x89, + 0x0d, 0x00, 0x00, 0x00, + 'h', 'a', 'l', 'f'}; + + Fir parsed; + EXPECT_FALSE(test::ParseSinglePacket(kPacketWithOneAndHalfFci, &parsed)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc new file mode 100644 index 0000000000..ba5a12b03a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc @@ -0,0 +1,174 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" + +#include <algorithm> +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Nack::kFeedbackMessageType; +constexpr size_t Nack::kNackItemLength; +// RFC 4585: Feedback format. +// +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | SSRC of media source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : Feedback Control Information (FCI) : +// : : +// +// Generic NACK (RFC 4585). +// +// FCI: +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | PID | BLP | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Nack::Nack() {} +Nack::~Nack() {} + +bool Nack::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + + if (packet.payload_size_bytes() < kCommonFeedbackLength + kNackItemLength) { + RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes() + << " is too small for a Nack."; + return false; + } + size_t nack_items = + (packet.payload_size_bytes() - kCommonFeedbackLength) / kNackItemLength; + + ParseCommonFeedback(packet.payload()); + const uint8_t* next_nack = packet.payload() + kCommonFeedbackLength; + + packet_ids_.clear(); + packed_.resize(nack_items); + for (size_t index = 0; index < nack_items; ++index) { + packed_[index].first_pid = ByteReader<uint16_t>::ReadBigEndian(next_nack); + packed_[index].bitmask = ByteReader<uint16_t>::ReadBigEndian(next_nack + 2); + next_nack += kNackItemLength; + } + Unpack(); + + return true; +} + +size_t Nack::BlockLength() const { + return kHeaderLength + kCommonFeedbackLength + + packed_.size() * kNackItemLength; +} + +bool Nack::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + RTC_DCHECK(!packed_.empty()); + // If nack list can't fit in packet, try to fragment. + constexpr size_t kNackHeaderLength = kHeaderLength + kCommonFeedbackLength; + for (size_t nack_index = 0; nack_index < packed_.size();) { + size_t bytes_left_in_buffer = max_length - *index; + if (bytes_left_in_buffer < kNackHeaderLength + kNackItemLength) { + if (!OnBufferFull(packet, index, callback)) + return false; + continue; + } + size_t num_nack_fields = + std::min((bytes_left_in_buffer - kNackHeaderLength) / kNackItemLength, + packed_.size() - nack_index); + + size_t payload_size_bytes = + kCommonFeedbackLength + (num_nack_fields * kNackItemLength); + size_t payload_size_32bits = + rtc::CheckedDivExact<size_t>(payload_size_bytes, 4); + CreateHeader(kFeedbackMessageType, kPacketType, payload_size_32bits, packet, + index); + + CreateCommonFeedback(packet + *index); + *index += kCommonFeedbackLength; + + size_t nack_end_index = nack_index + num_nack_fields; + for (; nack_index < nack_end_index; ++nack_index) { + const PackedNack& item = packed_[nack_index]; + ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 0, item.first_pid); + ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 2, item.bitmask); + *index += kNackItemLength; + } + RTC_DCHECK_LE(*index, max_length); + } + + return true; +} + +void Nack::SetPacketIds(const uint16_t* nack_list, size_t length) { + RTC_DCHECK(nack_list); + SetPacketIds(std::vector<uint16_t>(nack_list, nack_list + length)); +} + +void Nack::SetPacketIds(std::vector<uint16_t> nack_list) { + RTC_DCHECK(packet_ids_.empty()); + RTC_DCHECK(packed_.empty()); + packet_ids_ = std::move(nack_list); + Pack(); +} + +void Nack::Pack() { + RTC_DCHECK(!packet_ids_.empty()); + RTC_DCHECK(packed_.empty()); + auto it = packet_ids_.begin(); + const auto end = packet_ids_.end(); + while (it != end) { + PackedNack item; + item.first_pid = *it++; + // Bitmask specifies losses in any of the 16 packets following the pid. + item.bitmask = 0; + while (it != end) { + uint16_t shift = static_cast<uint16_t>(*it - item.first_pid - 1); + if (shift <= 15) { + item.bitmask |= (1 << shift); + ++it; + } else { + break; + } + } + packed_.push_back(item); + } +} + +void Nack::Unpack() { + RTC_DCHECK(packet_ids_.empty()); + RTC_DCHECK(!packed_.empty()); + for (const PackedNack& item : packed_) { + packet_ids_.push_back(item.first_pid); + uint16_t pid = item.first_pid + 1; + for (uint16_t bitmask = item.bitmask; bitmask != 0; bitmask >>= 1, ++pid) { + if (bitmask & 1) + packet_ids_.push_back(pid); + } + } +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h new file mode 100644 index 0000000000..13a590f6c5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h @@ -0,0 +1,59 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +class Nack : public Rtpfb { + public: + static constexpr uint8_t kFeedbackMessageType = 1; + Nack(); + ~Nack() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void SetPacketIds(const uint16_t* nack_list, size_t length); + void SetPacketIds(std::vector<uint16_t> nack_list); + const std::vector<uint16_t>& packet_ids() const { return packet_ids_; } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static constexpr size_t kNackItemLength = 4; + struct PackedNack { + uint16_t first_pid; + uint16_t bitmask; + }; + + void Pack(); // Fills packed_ using packed_ids_. (used in SetPacketIds). + void Unpack(); // Fills packet_ids_ using packed_. (used in Parse). + + std::vector<PackedNack> packed_; + std::vector<uint16_t> packet_ids_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc new file mode 100644 index 0000000000..ef5b5b639b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc @@ -0,0 +1,178 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +namespace webrtc { +namespace { + +using ::testing::_; +using ::testing::ElementsAreArray; +using ::testing::Invoke; +using ::testing::make_tuple; +using ::testing::UnorderedElementsAreArray; +using ::webrtc::rtcp::Nack; + +constexpr uint32_t kSenderSsrc = 0x12345678; +constexpr uint32_t kRemoteSsrc = 0x23456789; + +constexpr uint16_t kList[] = {0, 1, 3, 8, 16}; +constexpr size_t kListLength = sizeof(kList) / sizeof(kList[0]); +constexpr uint8_t kVersionBits = 2 << 6; +// clang-format off +constexpr uint8_t kPacket[] = { + kVersionBits | Nack::kFeedbackMessageType, Nack::kPacketType, 0, 3, + 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89, + 0x00, 0x00, 0x80, 0x85}; + +constexpr uint16_t kWrapList[] = {0xffdc, 0xffec, 0xfffe, 0xffff, 0x0000, + 0x0001, 0x0003, 0x0014, 0x0064}; +constexpr size_t kWrapListLength = sizeof(kWrapList) / sizeof(kWrapList[0]); +constexpr uint8_t kWrapPacket[] = { + kVersionBits | Nack::kFeedbackMessageType, Nack::kPacketType, 0, 6, + 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89, + 0xff, 0xdc, 0x80, 0x00, + 0xff, 0xfe, 0x00, 0x17, + 0x00, 0x14, 0x00, 0x00, + 0x00, 0x64, 0x00, 0x00}; +constexpr uint8_t kTooSmallPacket[] = { + kVersionBits | Nack::kFeedbackMessageType, Nack::kPacketType, 0, 2, + 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89}; +// clang-format on +} // namespace + +TEST(RtcpPacketNackTest, Create) { + Nack nack; + nack.SetSenderSsrc(kSenderSsrc); + nack.SetMediaSsrc(kRemoteSsrc); + nack.SetPacketIds(kList, kListLength); + + rtc::Buffer packet = nack.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketNackTest, Parse) { + Nack parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &parsed)); + const Nack& const_parsed = parsed; + + EXPECT_EQ(kSenderSsrc, const_parsed.sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, const_parsed.media_ssrc()); + EXPECT_THAT(const_parsed.packet_ids(), ElementsAreArray(kList)); +} + +TEST(RtcpPacketNackTest, CreateWrap) { + Nack nack; + nack.SetSenderSsrc(kSenderSsrc); + nack.SetMediaSsrc(kRemoteSsrc); + nack.SetPacketIds(kWrapList, kWrapListLength); + + rtc::Buffer packet = nack.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kWrapPacket)); +} + +TEST(RtcpPacketNackTest, ParseWrap) { + Nack parsed; + EXPECT_TRUE(test::ParseSinglePacket(kWrapPacket, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc()); + EXPECT_THAT(parsed.packet_ids(), ElementsAreArray(kWrapList)); +} + +TEST(RtcpPacketNackTest, BadOrder) { + // Does not guarantee optimal packing, but should guarantee correctness. + const uint16_t kUnorderedList[] = {1, 25, 13, 12, 9, 27, 29}; + const size_t kUnorderedListLength = + sizeof(kUnorderedList) / sizeof(kUnorderedList[0]); + Nack nack; + nack.SetSenderSsrc(kSenderSsrc); + nack.SetMediaSsrc(kRemoteSsrc); + nack.SetPacketIds(kUnorderedList, kUnorderedListLength); + + rtc::Buffer packet = nack.Build(); + + Nack parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc()); + EXPECT_THAT(parsed.packet_ids(), UnorderedElementsAreArray(kUnorderedList)); +} + +TEST(RtcpPacketNackTest, CreateFragmented) { + Nack nack; + const uint16_t kList[] = {1, 100, 200, 300, 400}; + const uint16_t kListLength = sizeof(kList) / sizeof(kList[0]); + nack.SetSenderSsrc(kSenderSsrc); + nack.SetMediaSsrc(kRemoteSsrc); + nack.SetPacketIds(kList, kListLength); + + class MockPacketReadyCallback : public rtcp::RtcpPacket::PacketReadyCallback { + public: + MOCK_METHOD2(OnPacketReady, void(uint8_t*, size_t)); + } verifier; + + class NackVerifier { + public: + explicit NackVerifier(std::vector<uint16_t> ids) : ids_(ids) {} + void operator()(uint8_t* data, size_t length) { + Nack nack; + EXPECT_TRUE(test::ParseSinglePacket(data, length, &nack)); + EXPECT_EQ(kSenderSsrc, nack.sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, nack.media_ssrc()); + EXPECT_THAT(nack.packet_ids(), ElementsAreArray(ids_)); + } + std::vector<uint16_t> ids_; + } packet1({1, 100, 200}), packet2({300, 400}); + + EXPECT_CALL(verifier, OnPacketReady(_, _)) + .WillOnce(Invoke(packet1)) + .WillOnce(Invoke(packet2)); + const size_t kBufferSize = 12 + (3 * 4); // Fits common header + 3 nack items + uint8_t buffer[kBufferSize]; + EXPECT_TRUE(nack.BuildExternalBuffer(buffer, kBufferSize, &verifier)); +} + +TEST(RtcpPacketNackTest, CreateFailsWithTooSmallBuffer) { + const uint16_t kList[] = {1}; + const size_t kMinNackBlockSize = 16; + Nack nack; + nack.SetSenderSsrc(kSenderSsrc); + nack.SetMediaSsrc(kRemoteSsrc); + nack.SetPacketIds(kList, 1); + class Verifier : public rtcp::RtcpPacket::PacketReadyCallback { + public: + void OnPacketReady(uint8_t* data, size_t length) override { + ADD_FAILURE() << "Buffer should be too small."; + } + } verifier; + uint8_t buffer[kMinNackBlockSize - 1]; + EXPECT_FALSE( + nack.BuildExternalBuffer(buffer, kMinNackBlockSize - 1, &verifier)); +} + +TEST(RtcpPacketNackTest, ParseFailsWithTooSmallBuffer) { + Nack parsed; + EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc new file mode 100644 index 0000000000..07fa259ca5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/pli.h" + +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Pli::kFeedbackMessageType; +// RFC 4585: Feedback format. +// +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of media source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : Feedback Control Information (FCI) : +// : : + +// +// Picture loss indication (PLI) (RFC 4585). +// FCI: no feedback control information. +bool Pli::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + + if (packet.payload_size_bytes() < kCommonFeedbackLength) { + RTC_LOG(LS_WARNING) << "Packet is too small to be a valid PLI packet"; + return false; + } + + ParseCommonFeedback(packet.payload()); + return true; +} + +size_t Pli::BlockLength() const { + return kHeaderLength + kCommonFeedbackLength; +} + +bool Pli::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, + index); + CreateCommonFeedback(packet + *index); + *index += kCommonFeedbackLength; + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h new file mode 100644 index 0000000000..f3c2fba960 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h @@ -0,0 +1,39 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_ + +#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; +// Picture loss indication (PLI) (RFC 4585). +class Pli : public Psfb { + public: + static constexpr uint8_t kFeedbackMessageType = 1; + + Pli() {} + ~Pli() override {} + + bool Parse(const CommonHeader& packet); + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc new file mode 100644 index 0000000000..e6cf7bef4a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/pli.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAreArray; +using testing::make_tuple; +using webrtc::rtcp::Pli; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrc = 0x23456789; +// Manually created Pli packet matching constants above. +const uint8_t kPacket[] = {0x81, 206, 0x00, 0x02, + 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89}; +} // namespace + +TEST(RtcpPacketPliTest, Parse) { + Pli mutable_parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &mutable_parsed)); + const Pli& parsed = mutable_parsed; // Read values from constant object. + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc()); +} + +TEST(RtcpPacketPliTest, Create) { + Pli pli; + pli.SetSenderSsrc(kSenderSsrc); + pli.SetMediaSsrc(kRemoteSsrc); + + rtc::Buffer packet = pli.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketPliTest, ParseFailsOnTooSmallPacket) { + const uint8_t kTooSmallPacket[] = {0x81, 206, 0x00, 0x01, + 0x12, 0x34, 0x56, 0x78}; + + Pli parsed; + EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc new file mode 100644 index 0000000000..074413a869 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h" + +#include "modules/rtp_rtcp/source/byte_io.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Psfb::kPacketType; +constexpr size_t Psfb::kCommonFeedbackLength; +// RFC 4585: Feedback format. +// +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | SSRC of media source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : Feedback Control Information (FCI) : +// : : + +void Psfb::ParseCommonFeedback(const uint8_t* payload) { + sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]); + media_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[4]); +} + +void Psfb::CreateCommonFeedback(uint8_t* payload) const { + ByteWriter<uint32_t>::WriteBigEndian(&payload[0], sender_ssrc_); + ByteWriter<uint32_t>::WriteBigEndian(&payload[4], media_ssrc_); +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h new file mode 100644 index 0000000000..33b7f1c9ef --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h @@ -0,0 +1,48 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_ + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { + +// PSFB: Payload-specific feedback message. +// RFC 4585, Section 6.3. +class Psfb : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 206; + + Psfb() : sender_ssrc_(0), media_ssrc_(0) {} + ~Psfb() override {} + + void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; } + void SetMediaSsrc(uint32_t ssrc) { media_ssrc_ = ssrc; } + + uint32_t sender_ssrc() const { return sender_ssrc_; } + uint32_t media_ssrc() const { return media_ssrc_; } + + protected: + static constexpr size_t kCommonFeedbackLength = 8; + void ParseCommonFeedback(const uint8_t* payload); + void CreateCommonFeedback(uint8_t* payload) const; + + private: + uint32_t sender_ssrc_; + uint32_t media_ssrc_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc new file mode 100644 index 0000000000..e79edbd825 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h" + +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t RapidResyncRequest::kFeedbackMessageType; +// RFC 4585: Feedback format. +// Rapid Resynchronisation Request (draft-perkins-avt-rapid-rtp-sync-03). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT=5 | PT=205 | length=2 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of media source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +bool RapidResyncRequest::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + + if (packet.payload_size_bytes() != kCommonFeedbackLength) { + RTC_LOG(LS_WARNING) << "Packet payload size should be " + << kCommonFeedbackLength << " instead of " + << packet.payload_size_bytes() + << " to be a valid Rapid Resynchronisation Request"; + return false; + } + + ParseCommonFeedback(packet.payload()); + return true; +} + +size_t RapidResyncRequest::BlockLength() const { + return kHeaderLength + kCommonFeedbackLength; +} + +bool RapidResyncRequest::Create( + uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, + index); + CreateCommonFeedback(packet + *index); + *index += kCommonFeedbackLength; + return true; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h new file mode 100644 index 0000000000..3e37295845 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_RAPID_RESYNC_REQUEST_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RAPID_RESYNC_REQUEST_H_ + +#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +// draft-perkins-avt-rapid-rtp-sync-03 +class RapidResyncRequest : public Rtpfb { + public: + static constexpr uint8_t kFeedbackMessageType = 5; + + RapidResyncRequest() {} + ~RapidResyncRequest() override {} + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& header); + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RAPID_RESYNC_REQUEST_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request_unittest.cc new file mode 100644 index 0000000000..e80736900d --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request_unittest.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAreArray; +using testing::make_tuple; +using webrtc::rtcp::RapidResyncRequest; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrc = 0x23456789; +// Manually created packet matching constants above. +const uint8_t kPacket[] = {0x85, 205, 0x00, 0x02, + 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89}; +} // namespace + +TEST(RtcpPacketRapidResyncRequestTest, Parse) { + RapidResyncRequest mutable_parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &mutable_parsed)); + const RapidResyncRequest& parsed = mutable_parsed; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc()); +} + +TEST(RtcpPacketRapidResyncRequestTest, Create) { + RapidResyncRequest rrr; + rrr.SetSenderSsrc(kSenderSsrc); + rrr.SetMediaSsrc(kRemoteSsrc); + + rtc::Buffer packet = rrr.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketRapidResyncRequestTest, ParseFailsOnTooSmallPacket) { + const uint8_t kTooSmallPacket[] = {0x85, 205, 0x00, 0x01, + 0x12, 0x34, 0x56, 0x78}; + RapidResyncRequest parsed; + EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed)); +} + +TEST(RtcpPacketRapidResyncRequestTest, ParseFailsOnTooLargePacket) { + const uint8_t kTooLargePacket[] = {0x85, 205, 0x00, 0x03, + 0x12, 0x34, 0x56, 0x78, + 0x32, 0x21, 0x65, 0x87, + 0x23, 0x45, 0x67, 0x89}; + RapidResyncRequest parsed; + EXPECT_FALSE(test::ParseSinglePacket(kTooLargePacket, &parsed)); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc new file mode 100644 index 0000000000..1654f48b34 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t ReceiverReport::kPacketType; +constexpr size_t ReceiverReport::kMaxNumberOfReportBlocks; +// RTCP receiver report (RFC 3550). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC | PT=RR=201 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | report block(s) | +// | .... | + +ReceiverReport::ReceiverReport() : sender_ssrc_(0) {} + +ReceiverReport::~ReceiverReport() = default; + +bool ReceiverReport::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + + const uint8_t report_blocks_count = packet.count(); + + if (packet.payload_size_bytes() < + kRrBaseLength + report_blocks_count * ReportBlock::kLength) { + RTC_LOG(LS_WARNING) << "Packet is too small to contain all the data."; + return false; + } + + sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(packet.payload()); + + const uint8_t* next_report_block = packet.payload() + kRrBaseLength; + + report_blocks_.resize(report_blocks_count); + for (ReportBlock& block : report_blocks_) { + block.Parse(next_report_block, ReportBlock::kLength); + next_report_block += ReportBlock::kLength; + } + + RTC_DCHECK_LE(next_report_block - packet.payload(), + static_cast<ptrdiff_t>(packet.payload_size_bytes())); + return true; +} + +size_t ReceiverReport::BlockLength() const { + return kHeaderLength + kRrBaseLength + + report_blocks_.size() * ReportBlock::kLength; +} + +bool ReceiverReport::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet, + index); + ByteWriter<uint32_t>::WriteBigEndian(packet + *index, sender_ssrc_); + *index += kRrBaseLength; + for (const ReportBlock& block : report_blocks_) { + block.Create(packet + *index); + *index += ReportBlock::kLength; + } + return true; +} + +bool ReceiverReport::AddReportBlock(const ReportBlock& block) { + if (report_blocks_.size() >= kMaxNumberOfReportBlocks) { + RTC_LOG(LS_WARNING) << "Max report blocks reached."; + return false; + } + report_blocks_.push_back(block); + return true; +} + +bool ReceiverReport::SetReportBlocks(std::vector<ReportBlock> blocks) { + if (blocks.size() > kMaxNumberOfReportBlocks) { + RTC_LOG(LS_WARNING) << "Too many report blocks (" << blocks.size() + << ") for receiver report."; + return false; + } + report_blocks_ = std::move(blocks); + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h new file mode 100644 index 0000000000..d8d828918a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h @@ -0,0 +1,60 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +class ReceiverReport : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 201; + static constexpr size_t kMaxNumberOfReportBlocks = 0x1f; + + ReceiverReport(); + ~ReceiverReport() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; } + bool AddReportBlock(const ReportBlock& block); + bool SetReportBlocks(std::vector<ReportBlock> blocks); + + uint32_t sender_ssrc() const { return sender_ssrc_; } + const std::vector<ReportBlock>& report_blocks() const { + return report_blocks_; + } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static const size_t kRrBaseLength = 4; + + uint32_t sender_ssrc_; + std::vector<ReportBlock> report_blocks_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc new file mode 100644 index 0000000000..8c105cd365 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc @@ -0,0 +1,161 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" + +#include <utility> + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAreArray; +using testing::IsEmpty; +using testing::make_tuple; +using webrtc::rtcp::ReceiverReport; +using webrtc::rtcp::ReportBlock; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrc = 0x23456789; +const uint8_t kFractionLost = 55; +const uint32_t kCumulativeLost = 0x111213; +const uint32_t kExtHighestSeqNum = 0x22232425; +const uint32_t kJitter = 0x33343536; +const uint32_t kLastSr = 0x44454647; +const uint32_t kDelayLastSr = 0x55565758; +// Manually created ReceiverReport with one ReportBlock matching constants +// above. +// Having this block allows to test Create and Parse separately. +const uint8_t kPacket[] = {0x81, 201, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89, 55, 0x11, 0x12, 0x13, + 0x22, 0x23, 0x24, 0x25, 0x33, 0x34, 0x35, 0x36, + 0x44, 0x45, 0x46, 0x47, 0x55, 0x56, 0x57, 0x58}; +} // namespace + +TEST(RtcpPacketReceiverReportTest, ParseWithOneReportBlock) { + ReceiverReport rr; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &rr)); + const ReceiverReport& parsed = rr; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(1u, parsed.report_blocks().size()); + const ReportBlock& rb = parsed.report_blocks().front(); + EXPECT_EQ(kRemoteSsrc, rb.source_ssrc()); + EXPECT_EQ(kFractionLost, rb.fraction_lost()); + EXPECT_EQ(kCumulativeLost, rb.cumulative_lost()); + EXPECT_EQ(kExtHighestSeqNum, rb.extended_high_seq_num()); + EXPECT_EQ(kJitter, rb.jitter()); + EXPECT_EQ(kLastSr, rb.last_sr()); + EXPECT_EQ(kDelayLastSr, rb.delay_since_last_sr()); +} + +TEST(RtcpPacketReceiverReportTest, ParseFailsOnIncorrectSize) { + rtc::Buffer damaged_packet(kPacket); + damaged_packet[0]++; // Damage the packet: increase count field. + ReceiverReport rr; + EXPECT_FALSE(test::ParseSinglePacket(damaged_packet, &rr)); +} + +TEST(RtcpPacketReceiverReportTest, CreateWithOneReportBlock) { + ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + ReportBlock rb; + rb.SetMediaSsrc(kRemoteSsrc); + rb.SetFractionLost(kFractionLost); + rb.SetCumulativeLost(kCumulativeLost); + rb.SetExtHighestSeqNum(kExtHighestSeqNum); + rb.SetJitter(kJitter); + rb.SetLastSr(kLastSr); + rb.SetDelayLastSr(kDelayLastSr); + rr.AddReportBlock(rb); + + rtc::Buffer raw = rr.Build(); + + EXPECT_THAT(make_tuple(raw.data(), raw.size()), ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketReceiverReportTest, CreateAndParseWithoutReportBlocks) { + ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + + rtc::Buffer raw = rr.Build(); + ReceiverReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_THAT(parsed.report_blocks(), IsEmpty()); +} + +TEST(RtcpPacketReceiverReportTest, CreateAndParseWithTwoReportBlocks) { + ReceiverReport rr; + ReportBlock rb1; + rb1.SetMediaSsrc(kRemoteSsrc); + ReportBlock rb2; + rb2.SetMediaSsrc(kRemoteSsrc + 1); + + rr.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(rr.AddReportBlock(rb1)); + EXPECT_TRUE(rr.AddReportBlock(rb2)); + + rtc::Buffer raw = rr.Build(); + ReceiverReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(2u, parsed.report_blocks().size()); + EXPECT_EQ(kRemoteSsrc, parsed.report_blocks()[0].source_ssrc()); + EXPECT_EQ(kRemoteSsrc + 1, parsed.report_blocks()[1].source_ssrc()); +} + +TEST(RtcpPacketReceiverReportTest, CreateWithTooManyReportBlocks) { + ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + ReportBlock rb; + for (size_t i = 0; i < ReceiverReport::kMaxNumberOfReportBlocks; ++i) { + rb.SetMediaSsrc(kRemoteSsrc + i); + EXPECT_TRUE(rr.AddReportBlock(rb)); + } + rb.SetMediaSsrc(kRemoteSsrc + ReceiverReport::kMaxNumberOfReportBlocks); + EXPECT_FALSE(rr.AddReportBlock(rb)); +} + +TEST(RtcpPacketReceiverReportTest, SetReportBlocksOverwritesOldBlocks) { + ReceiverReport rr; + ReportBlock report_block; + // Use jitter field of the report blocks to distinguish them. + report_block.SetJitter(1001u); + rr.AddReportBlock(report_block); + ASSERT_EQ(rr.report_blocks().size(), 1u); + ASSERT_EQ(rr.report_blocks()[0].jitter(), 1001u); + + std::vector<ReportBlock> blocks(3u); + blocks[0].SetJitter(2001u); + blocks[1].SetJitter(3001u); + blocks[2].SetJitter(4001u); + EXPECT_TRUE(rr.SetReportBlocks(blocks)); + ASSERT_EQ(rr.report_blocks().size(), 3u); + EXPECT_EQ(rr.report_blocks()[0].jitter(), 2001u); + EXPECT_EQ(rr.report_blocks()[1].jitter(), 3001u); + EXPECT_EQ(rr.report_blocks()[2].jitter(), 4001u); +} + +TEST(RtcpPacketReceiverReportTest, SetReportBlocksMaxLimit) { + ReceiverReport rr; + std::vector<ReportBlock> max_blocks(ReceiverReport::kMaxNumberOfReportBlocks); + EXPECT_TRUE(rr.SetReportBlocks(std::move(max_blocks))); + + std::vector<ReportBlock> one_too_many_blocks( + ReceiverReport::kMaxNumberOfReportBlocks + 1); + EXPECT_FALSE(rr.SetReportBlocks(std::move(one_too_many_blocks))); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.cc new file mode 100644 index 0000000000..981a296953 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/remb.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Remb::kFeedbackMessageType; +// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT=15 | PT=206 | length | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// 0 | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | Unused = 0 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | Unique identifier 'R' 'E' 'M' 'B' | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | Num SSRC | BR Exp | BR Mantissa | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | SSRC feedback | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : ... : + +Remb::Remb() : bitrate_bps_(0) {} + +Remb::~Remb() = default; + +bool Remb::Parse(const CommonHeader& packet) { + RTC_DCHECK(packet.type() == kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + + if (packet.payload_size_bytes() < 16) { + RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes() + << " is too small for Remb packet."; + return false; + } + const uint8_t* const payload = packet.payload(); + if (kUniqueIdentifier != ByteReader<uint32_t>::ReadBigEndian(&payload[8])) { + RTC_LOG(LS_WARNING) << "REMB identifier not found, not a REMB packet."; + return false; + } + uint8_t number_of_ssrcs = payload[12]; + if (packet.payload_size_bytes() != + kCommonFeedbackLength + (2 + number_of_ssrcs) * 4) { + RTC_LOG(LS_WARNING) << "Payload size " << packet.payload_size_bytes() + << " does not match " << number_of_ssrcs << " ssrcs."; + return false; + } + + ParseCommonFeedback(payload); + uint8_t exponenta = payload[13] >> 2; + uint64_t mantissa = (static_cast<uint32_t>(payload[13] & 0x03) << 16) | + ByteReader<uint16_t>::ReadBigEndian(&payload[14]); + bitrate_bps_ = (mantissa << exponenta); + bool shift_overflow = (bitrate_bps_ >> exponenta) != mantissa; + if (shift_overflow) { + RTC_LOG(LS_ERROR) << "Invalid remb bitrate value : " << mantissa << "*2^" + << static_cast<int>(exponenta); + return false; + } + + const uint8_t* next_ssrc = payload + 16; + ssrcs_.clear(); + ssrcs_.reserve(number_of_ssrcs); + for (uint8_t i = 0; i < number_of_ssrcs; ++i) { + ssrcs_.push_back(ByteReader<uint32_t>::ReadBigEndian(next_ssrc)); + next_ssrc += sizeof(uint32_t); + } + + return true; +} + +bool Remb::SetSsrcs(std::vector<uint32_t> ssrcs) { + if (ssrcs.size() > kMaxNumberOfSsrcs) { + RTC_LOG(LS_WARNING) << "Not enough space for all given SSRCs."; + return false; + } + ssrcs_ = std::move(ssrcs); + return true; +} + +size_t Remb::BlockLength() const { + return kHeaderLength + kCommonFeedbackLength + (2 + ssrcs_.size()) * 4; +} + +bool Remb::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + size_t index_end = *index + BlockLength(); + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, + index); + RTC_DCHECK_EQ(0, Psfb::media_ssrc()); + CreateCommonFeedback(packet + *index); + *index += kCommonFeedbackLength; + + ByteWriter<uint32_t>::WriteBigEndian(packet + *index, kUniqueIdentifier); + *index += sizeof(uint32_t); + const uint32_t kMaxMantissa = 0x3ffff; // 18 bits. + uint64_t mantissa = bitrate_bps_; + uint8_t exponenta = 0; + while (mantissa > kMaxMantissa) { + mantissa >>= 1; + ++exponenta; + } + packet[(*index)++] = static_cast<uint8_t>(ssrcs_.size()); + packet[(*index)++] = (exponenta << 2) | (mantissa >> 16); + ByteWriter<uint16_t>::WriteBigEndian(packet + *index, mantissa & 0xffff); + *index += sizeof(uint16_t); + + for (uint32_t ssrc : ssrcs_) { + ByteWriter<uint32_t>::WriteBigEndian(packet + *index, ssrc); + *index += sizeof(uint32_t); + } + RTC_DCHECK_EQ(index_end, *index); + return true; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h new file mode 100644 index 0000000000..1b01125169 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_REMB_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMB_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb). +class Remb : public Psfb { + public: + static constexpr uint8_t kFeedbackMessageType = 15; + static constexpr size_t kMaxNumberOfSsrcs = 0xff; + + Remb(); + ~Remb() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + bool SetSsrcs(std::vector<uint32_t> ssrcs); + void SetBitrateBps(uint64_t bitrate_bps) { bitrate_bps_ = bitrate_bps; } + + uint64_t bitrate_bps() const { return bitrate_bps_; } + const std::vector<uint32_t>& ssrcs() const { return ssrcs_; } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static constexpr uint32_t kUniqueIdentifier = 0x52454D42; // 'R' 'E' 'M' 'B'. + + // Media ssrc is unused, shadow base class setter and getter. + void SetMediaSsrc(uint32_t); + uint32_t media_ssrc() const; + + uint64_t bitrate_bps_; + std::vector<uint32_t> ssrcs_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMB_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb_unittest.cc new file mode 100644 index 0000000000..c939d9b41c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb_unittest.cc @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/remb.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAreArray; +using testing::IsEmpty; +using testing::make_tuple; +using webrtc::rtcp::Remb; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrcs[] = {0x23456789, 0x2345678a, 0x2345678b}; +const uint32_t kBitrateBps = 0x3fb93 * 2; // 522022; +const uint64_t kBitrateBps64bit = 0x3fb93ULL << 30; +const uint8_t kPacket[] = {0x8f, 206, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, 'R', 'E', 'M', 'B', + 0x03, 0x07, 0xfb, 0x93, 0x23, 0x45, 0x67, 0x89, + 0x23, 0x45, 0x67, 0x8a, 0x23, 0x45, 0x67, 0x8b}; +const size_t kPacketLength = sizeof(kPacket); +} // namespace + +TEST(RtcpPacketRembTest, Create) { + Remb remb; + remb.SetSenderSsrc(kSenderSsrc); + remb.SetSsrcs( + std::vector<uint32_t>(std::begin(kRemoteSsrcs), std::end(kRemoteSsrcs))); + remb.SetBitrateBps(kBitrateBps); + + rtc::Buffer packet = remb.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketRembTest, Parse) { + Remb remb; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &remb)); + const Remb& parsed = remb; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kBitrateBps, parsed.bitrate_bps()); + EXPECT_THAT(parsed.ssrcs(), ElementsAreArray(kRemoteSsrcs)); +} + +TEST(RtcpPacketRembTest, CreateAndParseWithoutSsrcs) { + Remb remb; + remb.SetSenderSsrc(kSenderSsrc); + remb.SetBitrateBps(kBitrateBps); + rtc::Buffer packet = remb.Build(); + + Remb parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kBitrateBps, parsed.bitrate_bps()); + EXPECT_THAT(parsed.ssrcs(), IsEmpty()); +} + +TEST(RtcpPacketRembTest, CreateAndParse64bitBitrate) { + Remb remb; + remb.SetBitrateBps(kBitrateBps64bit); + rtc::Buffer packet = remb.Build(); + + Remb parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + EXPECT_EQ(kBitrateBps64bit, parsed.bitrate_bps()); +} + +TEST(RtcpPacketRembTest, ParseFailsOnTooSmallPacketToBeRemb) { + // Make it too small. + constexpr size_t kTooSmallSize = (1 + 3) * 4; + uint8_t packet[kTooSmallSize]; + memcpy(packet, kPacket, kTooSmallSize); + packet[3] = 3; + + Remb remb; + EXPECT_FALSE(test::ParseSinglePacket(packet, &remb)); +} + +TEST(RtcpPacketRembTest, ParseFailsWhenUniqueIdentifierIsNotRemb) { + uint8_t packet[kPacketLength]; + memcpy(packet, kPacket, kPacketLength); + packet[12] = 'N'; // Swap 'R' -> 'N' in the 'REMB' unique identifier. + + Remb remb; + EXPECT_FALSE(test::ParseSinglePacket(packet, &remb)); +} + +TEST(RtcpPacketRembTest, ParseFailsWhenBitrateDoNotFitIn64bits) { + uint8_t packet[kPacketLength]; + memcpy(packet, kPacket, kPacketLength); + packet[17] |= 0xfc; // Set exponenta component to maximum of 63. + packet[19] |= 0x02; // Ensure mantissa is at least 2. + + Remb remb; + EXPECT_FALSE(test::ParseSinglePacket(packet, &remb)); +} + +TEST(RtcpPacketRembTest, ParseFailsWhenSsrcCountMismatchLength) { + uint8_t packet[kPacketLength]; + memcpy(packet, kPacket, kPacketLength); + packet[16]++; // Swap 3 -> 4 in the ssrcs count. + + Remb remb; + EXPECT_FALSE(test::ParseSinglePacket(packet, &remb)); +} + +TEST(RtcpPacketRembTest, TooManySsrcs) { + Remb remb; + EXPECT_FALSE(remb.SetSsrcs( + std::vector<uint32_t>(Remb::kMaxNumberOfSsrcs + 1, kRemoteSsrcs[0]))); + EXPECT_TRUE(remb.SetSsrcs( + std::vector<uint32_t>(Remb::kMaxNumberOfSsrcs, kRemoteSsrcs[0]))); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc new file mode 100644 index 0000000000..db84b6cfed --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { + +// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications. +// +// RTCP report block (RFC 3550). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// 0 | SSRC_1 (SSRC of first source) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | fraction lost | cumulative number of packets lost | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | extended highest sequence number received | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | interarrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | last SR (LSR) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 20 | delay since last SR (DLSR) | +// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +ReportBlock::ReportBlock() + : source_ssrc_(0), + fraction_lost_(0), + cumulative_lost_(0), + extended_high_seq_num_(0), + jitter_(0), + last_sr_(0), + delay_since_last_sr_(0) {} + +bool ReportBlock::Parse(const uint8_t* buffer, size_t length) { + RTC_DCHECK(buffer != nullptr); + if (length < ReportBlock::kLength) { + RTC_LOG(LS_ERROR) << "Report Block should be 24 bytes long"; + return false; + } + + source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[0]); + fraction_lost_ = buffer[4]; + cumulative_lost_ = ByteReader<uint32_t, 3>::ReadBigEndian(&buffer[5]); + extended_high_seq_num_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]); + jitter_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[12]); + last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[16]); + delay_since_last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[20]); + + return true; +} + +void ReportBlock::Create(uint8_t* buffer) const { + // Runtime check should be done while setting cumulative_lost. + RTC_DCHECK_LT(cumulative_lost(), (1 << 24)); // Have only 3 bytes for it. + + ByteWriter<uint32_t>::WriteBigEndian(&buffer[0], source_ssrc()); + ByteWriter<uint8_t>::WriteBigEndian(&buffer[4], fraction_lost()); + ByteWriter<uint32_t, 3>::WriteBigEndian(&buffer[5], cumulative_lost()); + ByteWriter<uint32_t>::WriteBigEndian(&buffer[8], extended_high_seq_num()); + ByteWriter<uint32_t>::WriteBigEndian(&buffer[12], jitter()); + ByteWriter<uint32_t>::WriteBigEndian(&buffer[16], last_sr()); + ByteWriter<uint32_t>::WriteBigEndian(&buffer[20], delay_since_last_sr()); +} + +bool ReportBlock::SetCumulativeLost(uint32_t cumulative_lost) { + if (cumulative_lost >= (1u << 24)) { // Have only 3 bytes to store it. + RTC_LOG(LS_WARNING) + << "Cumulative lost is too big to fit into Report Block"; + return false; + } + cumulative_lost_ = cumulative_lost; + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h new file mode 100644 index 0000000000..0d5c2fe6da --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h @@ -0,0 +1,67 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_ + +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { + +class ReportBlock { + public: + static const size_t kLength = 24; + + ReportBlock(); + ~ReportBlock() {} + + bool Parse(const uint8_t* buffer, size_t length); + + // Fills buffer with the ReportBlock. + // Consumes ReportBlock::kLength bytes. + void Create(uint8_t* buffer) const; + + void SetMediaSsrc(uint32_t ssrc) { source_ssrc_ = ssrc; } + void SetFractionLost(uint8_t fraction_lost) { + fraction_lost_ = fraction_lost; + } + bool SetCumulativeLost(uint32_t cumulative_lost); + void SetExtHighestSeqNum(uint32_t ext_highest_seq_num) { + extended_high_seq_num_ = ext_highest_seq_num; + } + void SetJitter(uint32_t jitter) { jitter_ = jitter; } + void SetLastSr(uint32_t last_sr) { last_sr_ = last_sr; } + void SetDelayLastSr(uint32_t delay_last_sr) { + delay_since_last_sr_ = delay_last_sr; + } + + uint32_t source_ssrc() const { return source_ssrc_; } + uint8_t fraction_lost() const { return fraction_lost_; } + uint32_t cumulative_lost() const { return cumulative_lost_; } + uint32_t extended_high_seq_num() const { return extended_high_seq_num_; } + uint32_t jitter() const { return jitter_; } + uint32_t last_sr() const { return last_sr_; } + uint32_t delay_since_last_sr() const { return delay_since_last_sr_; } + + private: + uint32_t source_ssrc_; + uint8_t fraction_lost_; + uint32_t cumulative_lost_; + uint32_t extended_high_seq_num_; + uint32_t jitter_; + uint32_t last_sr_; + uint32_t delay_since_last_sr_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc new file mode 100644 index 0000000000..38f8104933 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" + +#include <limits> + +#include "rtc_base/random.h" +#include "test/gtest.h" + +using webrtc::rtcp::ReportBlock; + +namespace webrtc { +namespace { + +const uint32_t kRemoteSsrc = 0x23456789; +const uint8_t kFractionLost = 55; +// Use values that are streamed differently LE and BE. +const uint32_t kCumulativeLost = 0x111213; +const uint32_t kExtHighestSeqNum = 0x22232425; +const uint32_t kJitter = 0x33343536; +const uint32_t kLastSr = 0x44454647; +const uint32_t kDelayLastSr = 0x55565758; +const size_t kBufferLength = ReportBlock::kLength; + +TEST(RtcpPacketReportBlockTest, ParseChecksLength) { + uint8_t buffer[kBufferLength]; + memset(buffer, 0, sizeof(buffer)); + + ReportBlock rb; + EXPECT_FALSE(rb.Parse(buffer, kBufferLength - 1)); + EXPECT_TRUE(rb.Parse(buffer, kBufferLength)); +} + +TEST(RtcpPacketReportBlockTest, ParseAnyData) { + uint8_t buffer[kBufferLength]; + // Fill buffer with semi-random data. + Random generator(0x256F8A285EC829ull); + for (size_t i = 0; i < kBufferLength; ++i) + buffer[i] = static_cast<uint8_t>(generator.Rand(0, 0xff)); + + ReportBlock rb; + EXPECT_TRUE(rb.Parse(buffer, kBufferLength)); +} + +TEST(RtcpPacketReportBlockTest, ParseMatchCreate) { + ReportBlock rb; + rb.SetMediaSsrc(kRemoteSsrc); + rb.SetFractionLost(kFractionLost); + rb.SetCumulativeLost(kCumulativeLost); + rb.SetExtHighestSeqNum(kExtHighestSeqNum); + rb.SetJitter(kJitter); + rb.SetLastSr(kLastSr); + rb.SetDelayLastSr(kDelayLastSr); + + uint8_t buffer[kBufferLength]; + rb.Create(buffer); + + ReportBlock parsed; + EXPECT_TRUE(parsed.Parse(buffer, kBufferLength)); + + EXPECT_EQ(kRemoteSsrc, parsed.source_ssrc()); + EXPECT_EQ(kFractionLost, parsed.fraction_lost()); + EXPECT_EQ(kCumulativeLost, parsed.cumulative_lost()); + EXPECT_EQ(kExtHighestSeqNum, parsed.extended_high_seq_num()); + EXPECT_EQ(kJitter, parsed.jitter()); + EXPECT_EQ(kLastSr, parsed.last_sr()); + EXPECT_EQ(kDelayLastSr, parsed.delay_since_last_sr()); +} + +TEST(RtcpPacketReportBlockTest, ValidateCumulativeLost) { + const uint32_t kMaxCumulativeLost = 0xffffff; + ReportBlock rb; + EXPECT_FALSE(rb.SetCumulativeLost(kMaxCumulativeLost + 1)); + EXPECT_TRUE(rb.SetCumulativeLost(kMaxCumulativeLost)); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc new file mode 100644 index 0000000000..95fc890b19 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace rtcp { +// Receiver Reference Time Report Block (RFC 3611). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | BT=4 | reserved | block length = 2 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | NTP timestamp, most significant word | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | NTP timestamp, least significant word | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +void Rrtr::Parse(const uint8_t* buffer) { + RTC_DCHECK(buffer[0] == kBlockType); + // reserved = buffer[1]; + RTC_DCHECK(ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) == kBlockLength); + uint32_t seconds = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]); + uint32_t fraction = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]); + ntp_.Set(seconds, fraction); +} + +void Rrtr::Create(uint8_t* buffer) const { + const uint8_t kReserved = 0; + buffer[0] = kBlockType; + buffer[1] = kReserved; + ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockLength); + ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], ntp_.seconds()); + ByteWriter<uint32_t>::WriteBigEndian(&buffer[8], ntp_.fractions()); +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h new file mode 100644 index 0000000000..9eae8c8922 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h @@ -0,0 +1,49 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_ + +#include "rtc_base/basictypes.h" +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { +namespace rtcp { + +class Rrtr { + public: + static const uint8_t kBlockType = 4; + static const uint16_t kBlockLength = 2; + static const size_t kLength = 4 * (kBlockLength + 1); // 12 + + Rrtr() {} + Rrtr(const Rrtr&) = default; + ~Rrtr() {} + + Rrtr& operator=(const Rrtr&) = default; + + void Parse(const uint8_t* buffer); + + // Fills buffer with the Rrtr. + // Consumes Rrtr::kLength bytes. + void Create(uint8_t* buffer) const; + + void SetNtp(NtpTime ntp) { ntp_ = ntp; } + + NtpTime ntp() const { return ntp_; } + + private: + NtpTime ntp_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc new file mode 100644 index 0000000000..7bd79b311c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h" + +#include "test/gtest.h" + +using webrtc::rtcp::Rrtr; + +namespace webrtc { +namespace { + +const uint32_t kNtpSec = 0x12345678; +const uint32_t kNtpFrac = 0x23456789; +const uint8_t kBlock[] = {0x04, 0x00, 0x00, 0x02, + 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89}; +const size_t kBlockSizeBytes = sizeof(kBlock); +static_assert( + kBlockSizeBytes == Rrtr::kLength, + "Size of manually created Rrtr block should match class constant"); + +TEST(RtcpPacketRrtrTest, Create) { + uint8_t buffer[Rrtr::kLength]; + Rrtr rrtr; + rrtr.SetNtp(NtpTime(kNtpSec, kNtpFrac)); + + rrtr.Create(buffer); + EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes)); +} + +TEST(RtcpPacketRrtrTest, Parse) { + Rrtr read_rrtr; + read_rrtr.Parse(kBlock); + + // Run checks on const object to ensure all accessors have const modifier. + const Rrtr& parsed = read_rrtr; + + EXPECT_EQ(kNtpSec, parsed.ntp().seconds()); + EXPECT_EQ(kNtpFrac, parsed.ntp().fractions()); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc new file mode 100644 index 0000000000..9b13e9a744 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h" + +#include "modules/rtp_rtcp/source/byte_io.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Rtpfb::kPacketType; +// RFC 4585, Section 6.1: Feedback format. +// +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | SSRC of media source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : Feedback Control Information (FCI) : +// : : + +void Rtpfb::ParseCommonFeedback(const uint8_t* payload) { + sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]); + media_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[4]); +} + +void Rtpfb::CreateCommonFeedback(uint8_t* payload) const { + ByteWriter<uint32_t>::WriteBigEndian(&payload[0], sender_ssrc_); + ByteWriter<uint32_t>::WriteBigEndian(&payload[4], media_ssrc_); +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h new file mode 100644 index 0000000000..4b08106af4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h @@ -0,0 +1,48 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_ + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { + +// RTPFB: Transport layer feedback message. +// RFC4585, Section 6.2 +class Rtpfb : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 205; + + Rtpfb() : sender_ssrc_(0), media_ssrc_(0) {} + ~Rtpfb() override {} + + void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; } + void SetMediaSsrc(uint32_t ssrc) { media_ssrc_ = ssrc; } + + uint32_t sender_ssrc() const { return sender_ssrc_; } + uint32_t media_ssrc() const { return media_ssrc_; } + + protected: + static constexpr size_t kCommonFeedbackLength = 8; + void ParseCommonFeedback(const uint8_t* payload); + void CreateCommonFeedback(uint8_t* payload) const; + + private: + uint32_t sender_ssrc_; + uint32_t media_ssrc_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc new file mode 100644 index 0000000000..5fe9408324 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/sdes.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Sdes::kPacketType; +constexpr size_t Sdes::kMaxNumberOfChunks; +// Source Description (SDES) (RFC 3550). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// header |V=2|P| SC | PT=SDES=202 | length | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// chunk | SSRC/CSRC_1 | +// 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SDES items | +// | ... | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// chunk | SSRC/CSRC_2 | +// 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SDES items | +// | ... | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// Canonical End-Point Identifier SDES Item (CNAME) +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | CNAME=1 | length | user and domain name ... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +namespace { +const uint8_t kTerminatorTag = 0; +const uint8_t kCnameTag = 1; + +size_t ChunkSize(const Sdes::Chunk& chunk) { + // Chunk: + // SSRC/CSRC (4 bytes) | CNAME=1 (1 byte) | length (1 byte) | cname | padding. + size_t chunk_payload_size = 4 + 1 + 1 + chunk.cname.size(); + size_t padding_size = 4 - (chunk_payload_size % 4); // Minimum 1. + return chunk_payload_size + padding_size; +} +} // namespace + +Sdes::Sdes() : block_length_(RtcpPacket::kHeaderLength) {} + +Sdes::~Sdes() {} + +bool Sdes::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + + uint8_t number_of_chunks = packet.count(); + std::vector<Chunk> chunks; // Read chunk into temporary array, so that in + // case of an error original array would stay + // unchanged. + size_t block_length = kHeaderLength; + + if (packet.payload_size_bytes() % 4 != 0) { + RTC_LOG(LS_WARNING) << "Invalid payload size " + << packet.payload_size_bytes() + << " bytes for a valid Sdes packet. Size should be" + " multiple of 4 bytes"; + } + const uint8_t* const payload_end = + packet.payload() + packet.payload_size_bytes(); + const uint8_t* looking_at = packet.payload(); + chunks.resize(number_of_chunks); + for (size_t i = 0; i < number_of_chunks;) { + // Each chunk consumes at least 8 bytes. + if (payload_end - looking_at < 8) { + RTC_LOG(LS_WARNING) << "Not enough space left for chunk #" << (i + 1); + return false; + } + chunks[i].ssrc = ByteReader<uint32_t>::ReadBigEndian(looking_at); + looking_at += sizeof(uint32_t); + bool cname_found = false; + + uint8_t item_type; + while ((item_type = *(looking_at++)) != kTerminatorTag) { + if (looking_at >= payload_end) { + RTC_LOG(LS_WARNING) + << "Unexpected end of packet while reading chunk #" << (i + 1) + << ". Expected to find size of the text."; + return false; + } + uint8_t item_length = *(looking_at++); + const size_t kTerminatorSize = 1; + if (looking_at + item_length + kTerminatorSize > payload_end) { + RTC_LOG(LS_WARNING) + << "Unexpected end of packet while reading chunk #" << (i + 1) + << ". Expected to find text of size " << item_length; + return false; + } + if (item_type == kCnameTag) { + if (cname_found) { + RTC_LOG(LS_WARNING) + << "Found extra CNAME for same ssrc in chunk #" << (i + 1); + return false; + } + cname_found = true; + chunks[i].cname.assign(reinterpret_cast<const char*>(looking_at), + item_length); + } + looking_at += item_length; + } + if (cname_found) { + // block_length calculates length of the packet that would be generated by + // Build/Create functions. Adjust it same way WithCName function does. + block_length += ChunkSize(chunks[i]); + ++i; + } else { + // RFC states CNAME item is mandatory. + // But same time it allows chunk without items. + // So while parsing, ignore all chunks without cname, + // but do not fail the parse. + RTC_LOG(LS_WARNING) << "CNAME not found for ssrc " << chunks[i].ssrc; + --number_of_chunks; + chunks.resize(number_of_chunks); + } + // Adjust to 32bit boundary. + looking_at += (payload_end - looking_at) % 4; + } + + chunks_ = std::move(chunks); + block_length_ = block_length; + return true; +} + +bool Sdes::AddCName(uint32_t ssrc, std::string cname) { + RTC_DCHECK_LE(cname.length(), 0xffu); + if (chunks_.size() >= kMaxNumberOfChunks) { + RTC_LOG(LS_WARNING) << "Max SDES chunks reached."; + return false; + } + Chunk chunk; + chunk.ssrc = ssrc; + chunk.cname = std::move(cname); + chunks_.push_back(chunk); + block_length_ += ChunkSize(chunk); + return true; +} + +size_t Sdes::BlockLength() const { + return block_length_; +} + +bool Sdes::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + CreateHeader(chunks_.size(), kPacketType, HeaderLength(), packet, index); + + for (const Sdes::Chunk& chunk : chunks_) { + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], chunk.ssrc); + ByteWriter<uint8_t>::WriteBigEndian(&packet[*index + 4], kCnameTag); + ByteWriter<uint8_t>::WriteBigEndian( + &packet[*index + 5], static_cast<uint8_t>(chunk.cname.size())); + memcpy(&packet[*index + 6], chunk.cname.data(), chunk.cname.size()); + *index += (6 + chunk.cname.size()); + + // In each chunk, the list of items must be terminated by one or more null + // octets. The next chunk must start on a 32-bit boundary. + // CNAME (1 byte) | length (1 byte) | name | padding. + size_t padding_size = 4 - ((6 + chunk.cname.size()) % 4); + const int kPadding = 0; + memset(packet + *index, kPadding, padding_size); + *index += padding_size; + } + + RTC_CHECK_EQ(*index, index_end); + return true; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h new file mode 100644 index 0000000000..2eea09b3de --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_ + +#include <string> +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; +// Source Description (SDES) (RFC 3550). +class Sdes : public RtcpPacket { + public: + struct Chunk { + uint32_t ssrc; + std::string cname; + }; + static constexpr uint8_t kPacketType = 202; + static constexpr size_t kMaxNumberOfChunks = 0x1f; + + Sdes(); + ~Sdes() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + bool AddCName(uint32_t ssrc, std::string cname); + + const std::vector<Chunk>& chunks() const { return chunks_; } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + std::vector<Chunk> chunks_; + size_t block_length_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc new file mode 100644 index 0000000000..7896f2d0bc --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/sdes.h" + +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using webrtc::rtcp::Sdes; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint8_t kPadding = 0; +const uint8_t kTerminatorTag = 0; +const uint8_t kCnameTag = 1; +const uint8_t kNameTag = 2; +const uint8_t kEmailTag = 3; +} // namespace + +TEST(RtcpPacketSdesTest, CreateAndParseWithoutChunks) { + Sdes sdes; + + rtc::Buffer packet = sdes.Build(); + Sdes parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(0u, parsed.chunks().size()); +} + +TEST(RtcpPacketSdesTest, CreateAndParseWithOneChunk) { + const std::string kCname = "alice@host"; + + Sdes sdes; + EXPECT_TRUE(sdes.AddCName(kSenderSsrc, kCname)); + + rtc::Buffer packet = sdes.Build(); + Sdes sdes_parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &sdes_parsed)); + const Sdes& parsed = sdes_parsed; // Ensure accessors are const. + + EXPECT_EQ(1u, parsed.chunks().size()); + EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc); + EXPECT_EQ(kCname, parsed.chunks()[0].cname); +} + +TEST(RtcpPacketSdesTest, CreateAndParseWithMultipleChunks) { + Sdes sdes; + EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 0, "a")); + EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 1, "ab")); + EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 2, "abc")); + EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 3, "abcd")); + EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 4, "abcde")); + EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 5, "abcdef")); + + rtc::Buffer packet = sdes.Build(); + Sdes parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(6u, parsed.chunks().size()); + EXPECT_EQ(kSenderSsrc + 5, parsed.chunks()[5].ssrc); + EXPECT_EQ("abcdef", parsed.chunks()[5].cname); +} + +TEST(RtcpPacketSdesTest, CreateWithTooManyChunks) { + const size_t kMaxChunks = (1 << 5) - 1; + Sdes sdes; + for (size_t i = 0; i < kMaxChunks; ++i) { + uint32_t ssrc = kSenderSsrc + i; + std::ostringstream oss; + oss << "cname" << i; + EXPECT_TRUE(sdes.AddCName(ssrc, oss.str())); + } + EXPECT_FALSE(sdes.AddCName(kSenderSsrc + kMaxChunks, "foo")); +} + +TEST(RtcpPacketSdesTest, CreateAndParseCnameItemWithEmptyString) { + Sdes sdes; + EXPECT_TRUE(sdes.AddCName(kSenderSsrc, "")); + + rtc::Buffer packet = sdes.Build(); + Sdes parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(1u, parsed.chunks().size()); + EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc); + EXPECT_EQ("", parsed.chunks()[0].cname); +} + +TEST(RtcpPacketSdesTest, ParseSkipsNonCNameField) { + const uint8_t kName[] = "abc"; + const uint8_t kCname[] = "de"; + const uint8_t kValidPacket[] = {0x81, 202, 0x00, 0x04, + 0x12, 0x34, 0x56, 0x78, + kNameTag, 3, kName[0], kName[1], kName[2], + kCnameTag, 2, kCname[0], kCname[1], + kTerminatorTag, kPadding, kPadding}; + // Sanity checks packet was assembled correctly. + ASSERT_EQ(0u, sizeof(kValidPacket) % 4); + ASSERT_EQ(kValidPacket[3] + 1u, sizeof(kValidPacket) / 4); + + Sdes parsed; + EXPECT_TRUE(test::ParseSinglePacket(kValidPacket, &parsed)); + + EXPECT_EQ(1u, parsed.chunks().size()); + EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc); + EXPECT_EQ("de", parsed.chunks()[0].cname); +} + +TEST(RtcpPacketSdesTest, ParseSkipsChunksWithoutCName) { + const uint8_t kName[] = "ab"; + const uint8_t kEmail[] = "de"; + const uint8_t kCname[] = "def"; + const uint8_t kPacket[] = {0x82, 202, 0x00, 0x07, + 0x12, 0x34, 0x56, 0x78, // 1st chunk. + kNameTag, 3, kName[0], kName[1], kName[2], + kEmailTag, 2, kEmail[0], kEmail[1], + kTerminatorTag, kPadding, kPadding, + 0x23, 0x45, 0x67, 0x89, // 2nd chunk. + kCnameTag, 3, kCname[0], kCname[1], kCname[2], + kTerminatorTag, kPadding, kPadding}; + // Sanity checks packet was assembled correctly. + ASSERT_EQ(0u, sizeof(kPacket) % 4); + ASSERT_EQ(kPacket[3] + 1u, sizeof(kPacket) / 4); + + Sdes parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &parsed)); + ASSERT_EQ(1u, parsed.chunks().size()); + EXPECT_EQ(0x23456789u, parsed.chunks()[0].ssrc); + EXPECT_EQ("def", parsed.chunks()[0].cname); +} + +TEST(RtcpPacketSdesTest, ParseFailsWithoutChunkItemTerminator) { + const uint8_t kName[] = "abc"; + const uint8_t kCname[] = "d"; + // No place for next chunk item. + const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03, + 0x12, 0x34, 0x56, 0x78, + kNameTag, 3, kName[0], kName[1], kName[2], + kCnameTag, 1, kCname[0]}; + // Sanity checks packet was assembled correctly. + ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4); + ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4); + + Sdes parsed; + EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed)); +} + +TEST(RtcpPacketSdesTest, ParseFailsWithDamagedChunkItem) { + const uint8_t kName[] = "ab"; + const uint8_t kCname[] = "d"; + // Next chunk item has non-terminator type, but not the size. + const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03, + 0x12, 0x34, 0x56, 0x78, + kNameTag, 2, kName[0], kName[1], + kCnameTag, 1, kCname[0], + kEmailTag}; + // Sanity checks packet was assembled correctly. + ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4); + ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4); + + Sdes parsed; + EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed)); +} + +TEST(RtcpPacketSdesTest, ParseFailsWithTooLongChunkItem) { + const uint8_t kName[] = "abc"; + const uint8_t kCname[] = "d"; + // Last chunk item has length that goes beyond the buffer end. + const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03, + 0x12, 0x34, 0x56, 0x78, + kNameTag, 3, kName[0], kName[1], kName[2], + kCnameTag, 2, kCname[0]}; + // Sanity checks packet was assembled correctly. + ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4); + ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4); + + Sdes parsed; + EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed)); +} + +TEST(RtcpPacketSdesTest, ParseFailsWithTwoCNames) { + const uint8_t kCname1[] = "a"; + const uint8_t kCname2[] = "de"; + const uint8_t kInvalidPacket[] = {0x81, 202, 0x00, 0x03, + 0x12, 0x34, 0x56, 0x78, + kCnameTag, 1, kCname1[0], + kCnameTag, 2, kCname2[0], kCname2[1], + kTerminatorTag}; + // Sanity checks packet was assembled correctly. + ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4); + ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4); + + Sdes parsed; + EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed)); +} + +TEST(RtcpPacketSdesTest, ParseFailsWithTooLittleSpaceForNextChunk) { + const uint8_t kCname[] = "a"; + const uint8_t kEmail[] = "de"; + // Two chunks are promised in the header, but no place for the second chunk. + const uint8_t kInvalidPacket[] = {0x82, 202, 0x00, 0x04, + 0x12, 0x34, 0x56, 0x78, // 1st chunk. + kCnameTag, 1, kCname[0], + kEmailTag, 2, kEmail[0], kEmail[1], + kTerminatorTag, + 0x23, 0x45, 0x67, 0x89}; // 2nd chunk. + // Sanity checks packet was assembled correctly. + ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4); + ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4); + + Sdes parsed; + EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed)); +} + +TEST(RtcpPacketSdesTest, ParsedSdesCanBeReusedForBuilding) { + Sdes source; + const std::string kAlice = "alice@host"; + const std::string kBob = "bob@host"; + source.AddCName(kSenderSsrc, kAlice); + + rtc::Buffer packet1 = source.Build(); + Sdes middle; + test::ParseSinglePacket(packet1, &middle); + + EXPECT_EQ(source.BlockLength(), middle.BlockLength()); + + middle.AddCName(kSenderSsrc + 1, kBob); + + rtc::Buffer packet2 = middle.Build(); + Sdes destination; + test::ParseSinglePacket(packet2, &destination); + + EXPECT_EQ(middle.BlockLength(), destination.BlockLength()); + + EXPECT_EQ(2u, destination.chunks().size()); + EXPECT_EQ(kSenderSsrc, destination.chunks()[0].ssrc); + EXPECT_EQ(kAlice, destination.chunks()[0].cname); + EXPECT_EQ(kSenderSsrc + 1, destination.chunks()[1].ssrc); + EXPECT_EQ(kBob, destination.chunks()[1].cname); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc new file mode 100644 index 0000000000..637cbb6a45 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/sender_report.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t SenderReport::kPacketType; +constexpr size_t SenderReport::kMaxNumberOfReportBlocks; +// Sender report (SR) (RFC 3550). +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC | PT=SR=200 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC of sender | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// 4 | NTP timestamp, most significant word | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | NTP timestamp, least significant word | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | RTP timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | sender's packet count | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 20 | sender's octet count | +// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +SenderReport::SenderReport() + : sender_ssrc_(0), + rtp_timestamp_(0), + sender_packet_count_(0), + sender_octet_count_(0) {} + +SenderReport::~SenderReport() = default; + +bool SenderReport::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + + const uint8_t report_block_count = packet.count(); + if (packet.payload_size_bytes() < + kSenderBaseLength + report_block_count * ReportBlock::kLength) { + RTC_LOG(LS_WARNING) << "Packet is too small to contain all the data."; + return false; + } + // Read SenderReport header. + const uint8_t* const payload = packet.payload(); + sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]); + uint32_t secs = ByteReader<uint32_t>::ReadBigEndian(&payload[4]); + uint32_t frac = ByteReader<uint32_t>::ReadBigEndian(&payload[8]); + ntp_.Set(secs, frac); + rtp_timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&payload[12]); + sender_packet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[16]); + sender_octet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[20]); + report_blocks_.resize(report_block_count); + const uint8_t* next_block = payload + kSenderBaseLength; + for (ReportBlock& block : report_blocks_) { + bool block_parsed = block.Parse(next_block, ReportBlock::kLength); + RTC_DCHECK(block_parsed); + next_block += ReportBlock::kLength; + } + // Double check we didn't read beyond provided buffer. + RTC_DCHECK_LE(next_block - payload, + static_cast<ptrdiff_t>(packet.payload_size_bytes())); + return true; +} + +size_t SenderReport::BlockLength() const { + return kHeaderLength + kSenderBaseLength + + report_blocks_.size() * ReportBlock::kLength; +} + +bool SenderReport::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + + CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet, + index); + // Write SenderReport header. + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], sender_ssrc_); + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 4], ntp_.seconds()); + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 8], ntp_.fractions()); + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 12], rtp_timestamp_); + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 16], + sender_packet_count_); + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 20], + sender_octet_count_); + *index += kSenderBaseLength; + // Write report blocks. + for (const ReportBlock& block : report_blocks_) { + block.Create(packet + *index); + *index += ReportBlock::kLength; + } + // Ensure bytes written match expected. + RTC_DCHECK_EQ(*index, index_end); + return true; +} + +bool SenderReport::AddReportBlock(const ReportBlock& block) { + if (report_blocks_.size() >= kMaxNumberOfReportBlocks) { + RTC_LOG(LS_WARNING) << "Max report blocks reached."; + return false; + } + report_blocks_.push_back(block); + return true; +} + +bool SenderReport::SetReportBlocks(std::vector<ReportBlock> blocks) { + if (blocks.size() > kMaxNumberOfReportBlocks) { + RTC_LOG(LS_WARNING) << "Too many report blocks (" << blocks.size() + << ") for sender report."; + return false; + } + report_blocks_ = std::move(blocks); + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h new file mode 100644 index 0000000000..2cbfe72af9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +class SenderReport : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 200; + static constexpr size_t kMaxNumberOfReportBlocks = 0x1f; + + SenderReport(); + ~SenderReport() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; } + void SetNtp(NtpTime ntp) { ntp_ = ntp; } + void SetRtpTimestamp(uint32_t rtp_timestamp) { + rtp_timestamp_ = rtp_timestamp; + } + void SetPacketCount(uint32_t packet_count) { + sender_packet_count_ = packet_count; + } + void SetOctetCount(uint32_t octet_count) { + sender_octet_count_ = octet_count; + } + bool AddReportBlock(const ReportBlock& block); + bool SetReportBlocks(std::vector<ReportBlock> blocks); + void ClearReportBlocks() { report_blocks_.clear(); } + + uint32_t sender_ssrc() const { return sender_ssrc_; } + NtpTime ntp() const { return ntp_; } + uint32_t rtp_timestamp() const { return rtp_timestamp_; } + uint32_t sender_packet_count() const { return sender_packet_count_; } + uint32_t sender_octet_count() const { return sender_octet_count_; } + + const std::vector<ReportBlock>& report_blocks() const { + return report_blocks_; + } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + const size_t kSenderBaseLength = 24; + + uint32_t sender_ssrc_; + NtpTime ntp_; + uint32_t rtp_timestamp_; + uint32_t sender_packet_count_; + uint32_t sender_octet_count_; + std::vector<ReportBlock> report_blocks_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc new file mode 100644 index 0000000000..30edc7ecdb --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/sender_report.h" + +#include <utility> + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAreArray; +using testing::make_tuple; +using webrtc::rtcp::ReportBlock; +using webrtc::rtcp::SenderReport; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrc = 0x23456789; +const NtpTime kNtp(0x11121418, 0x22242628); +const uint32_t kRtpTimestamp = 0x33343536; +const uint32_t kPacketCount = 0x44454647; +const uint32_t kOctetCount = 0x55565758; +const uint8_t kPacket[] = {0x80, 200, 0x00, 0x06, + 0x12, 0x34, 0x56, 0x78, + 0x11, 0x12, 0x14, 0x18, + 0x22, 0x24, 0x26, 0x28, + 0x33, 0x34, 0x35, 0x36, + 0x44, 0x45, 0x46, 0x47, + 0x55, 0x56, 0x57, 0x58}; +} // namespace + +TEST(RtcpPacketSenderReportTest, CreateWithoutReportBlocks) { + SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + sr.SetNtp(kNtp); + sr.SetRtpTimestamp(kRtpTimestamp); + sr.SetPacketCount(kPacketCount); + sr.SetOctetCount(kOctetCount); + + rtc::Buffer raw = sr.Build(); + EXPECT_THAT(make_tuple(raw.data(), raw.size()), ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketSenderReportTest, ParseWithoutReportBlocks) { + SenderReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(kNtp, parsed.ntp()); + EXPECT_EQ(kRtpTimestamp, parsed.rtp_timestamp()); + EXPECT_EQ(kPacketCount, parsed.sender_packet_count()); + EXPECT_EQ(kOctetCount, parsed.sender_octet_count()); + EXPECT_TRUE(parsed.report_blocks().empty()); +} + +TEST(RtcpPacketSenderReportTest, CreateAndParseWithOneReportBlock) { + ReportBlock rb; + rb.SetMediaSsrc(kRemoteSsrc); + + SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(sr.AddReportBlock(rb)); + + rtc::Buffer raw = sr.Build(); + SenderReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(1u, parsed.report_blocks().size()); + EXPECT_EQ(kRemoteSsrc, parsed.report_blocks()[0].source_ssrc()); +} + +TEST(RtcpPacketSenderReportTest, CreateAndParseWithTwoReportBlocks) { + ReportBlock rb1; + rb1.SetMediaSsrc(kRemoteSsrc); + ReportBlock rb2; + rb2.SetMediaSsrc(kRemoteSsrc + 1); + + SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(sr.AddReportBlock(rb1)); + EXPECT_TRUE(sr.AddReportBlock(rb2)); + + rtc::Buffer raw = sr.Build(); + SenderReport parsed; + EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(2u, parsed.report_blocks().size()); + EXPECT_EQ(kRemoteSsrc, parsed.report_blocks()[0].source_ssrc()); + EXPECT_EQ(kRemoteSsrc + 1, parsed.report_blocks()[1].source_ssrc()); +} + +TEST(RtcpPacketSenderReportTest, CreateWithTooManyReportBlocks) { + SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + ReportBlock rb; + for (size_t i = 0; i < SenderReport::kMaxNumberOfReportBlocks; ++i) { + rb.SetMediaSsrc(kRemoteSsrc + i); + EXPECT_TRUE(sr.AddReportBlock(rb)); + } + rb.SetMediaSsrc(kRemoteSsrc + SenderReport::kMaxNumberOfReportBlocks); + EXPECT_FALSE(sr.AddReportBlock(rb)); +} + +TEST(RtcpPacketSenderReportTest, SetReportBlocksOverwritesOldBlocks) { + SenderReport sr; + ReportBlock report_block; + // Use jitter field of the report blocks to distinguish them. + report_block.SetJitter(1001u); + sr.AddReportBlock(report_block); + ASSERT_EQ(sr.report_blocks().size(), 1u); + ASSERT_EQ(sr.report_blocks()[0].jitter(), 1001u); + + std::vector<ReportBlock> blocks(3u); + blocks[0].SetJitter(2001u); + blocks[1].SetJitter(3001u); + blocks[2].SetJitter(4001u); + EXPECT_TRUE(sr.SetReportBlocks(blocks)); + ASSERT_EQ(sr.report_blocks().size(), 3u); + EXPECT_EQ(sr.report_blocks()[0].jitter(), 2001u); + EXPECT_EQ(sr.report_blocks()[1].jitter(), 3001u); + EXPECT_EQ(sr.report_blocks()[2].jitter(), 4001u); +} + +TEST(RtcpPacketSenderReportTest, SetReportBlocksMaxLimit) { + SenderReport sr; + std::vector<ReportBlock> max_blocks(SenderReport::kMaxNumberOfReportBlocks); + EXPECT_TRUE(sr.SetReportBlocks(std::move(max_blocks))); + + std::vector<ReportBlock> one_too_many_blocks( + SenderReport::kMaxNumberOfReportBlocks + 1); + EXPECT_FALSE(sr.SetReportBlocks(std::move(one_too_many_blocks))); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc new file mode 100644 index 0000000000..601b24fe94 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/target_bitrate.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { +namespace rtcp { +constexpr size_t kTargetBitrateHeaderSizeBytes = 4; +constexpr uint8_t TargetBitrate::kBlockType; +const size_t TargetBitrate::kBitrateItemSizeBytes = 4; + +TargetBitrate::BitrateItem::BitrateItem() + : spatial_layer(0), temporal_layer(0), target_bitrate_kbps(0) {} + +TargetBitrate::BitrateItem::BitrateItem(uint8_t spatial_layer, + uint8_t temporal_layer, + uint32_t target_bitrate_kbps) + : spatial_layer(spatial_layer), + temporal_layer(temporal_layer), + target_bitrate_kbps(target_bitrate_kbps) {} + +// RFC 4585: Feedback format. +// +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | BT=42 | reserved | block length | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// Target bitrate item (repeat as many times as necessary). +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | S | T | Target Bitrate | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : ... : +// +// Spatial Layer (S): 4 bits +// Indicates which temporal layer this bitrate concerns. +// +// Temporal Layer (T): 4 bits +// Indicates which temporal layer this bitrate concerns. +// +// Target Bitrate: 24 bits +// The encoder target bitrate for this layer, in kbps. +// +// As an example of how S and T are intended to be used, VP8 simulcast will +// use a separate TargetBitrate message per stream, since they are transmitted +// on separate SSRCs, with temporal layers grouped by stream. +// If VP9 SVC is used, there will be only one SSRC, so each spatial and +// temporal layer combo used shall be specified in the TargetBitrate packet. + +TargetBitrate::TargetBitrate() = default; +TargetBitrate::TargetBitrate(const TargetBitrate&) = default; +TargetBitrate& TargetBitrate::operator=(const TargetBitrate&) = default; +TargetBitrate::~TargetBitrate() = default; + +void TargetBitrate::Parse(const uint8_t* block, uint16_t block_length) { + // Validate block header (should already have been parsed and checked). + RTC_DCHECK_EQ(block[0], kBlockType); + RTC_DCHECK_EQ(block_length, ByteReader<uint16_t>::ReadBigEndian(&block[2])); + + // Header specifies block length - 1, but since we ignore the header, which + // occupies exactly on block, we can just treat this as payload length. + const size_t payload_bytes = block_length * 4; + const size_t num_items = payload_bytes / kBitrateItemSizeBytes; + size_t index = kTargetBitrateHeaderSizeBytes; + bitrates_.clear(); + for (size_t i = 0; i < num_items; ++i) { + uint8_t layers = block[index]; + uint32_t bitrate_kbps = + ByteReader<uint32_t, 3>::ReadBigEndian(&block[index + 1]); + index += kBitrateItemSizeBytes; + AddTargetBitrate((layers >> 4) & 0x0F, layers & 0x0F, bitrate_kbps); + } +} + +void TargetBitrate::AddTargetBitrate(uint8_t spatial_layer, + uint8_t temporal_layer, + uint32_t target_bitrate_kbps) { + RTC_DCHECK_LE(spatial_layer, 0x0F); + RTC_DCHECK_LE(temporal_layer, 0x0F); + RTC_DCHECK_LE(target_bitrate_kbps, 0x00FFFFFFU); + bitrates_.push_back( + BitrateItem(spatial_layer, temporal_layer, target_bitrate_kbps)); +} + +const std::vector<TargetBitrate::BitrateItem>& +TargetBitrate::GetTargetBitrates() const { + return bitrates_; +} + +size_t TargetBitrate::BlockLength() const { + return kTargetBitrateHeaderSizeBytes + + bitrates_.size() * kBitrateItemSizeBytes; +} + +void TargetBitrate::Create(uint8_t* buffer) const { + buffer[0] = kBlockType; + buffer[1] = 0; // Reserved. + uint16_t block_length_words = + rtc::dchecked_cast<uint16_t>((BlockLength() / 4) - 1); + ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], block_length_words); + + size_t index = kTargetBitrateHeaderSizeBytes; + for (const BitrateItem& item : bitrates_) { + buffer[index] = (item.spatial_layer << 4) | item.temporal_layer; + ByteWriter<uint32_t, 3>::WriteBigEndian(&buffer[index + 1], + item.target_bitrate_kbps); + index += kBitrateItemSizeBytes; + } +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h new file mode 100644 index 0000000000..a3793e320b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_TARGET_BITRATE_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TARGET_BITRATE_H_ + +#include <vector> + +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { + +class TargetBitrate { + public: + // TODO(sprang): This block type is just a place holder. We need to get an + // id assigned by IANA. + static constexpr uint8_t kBlockType = 42; + static const size_t kBitrateItemSizeBytes; + + struct BitrateItem { + BitrateItem(); + BitrateItem(uint8_t spatial_layer, + uint8_t temporal_layer, + uint32_t target_bitrate_kbps); + + uint8_t spatial_layer; + uint8_t temporal_layer; + uint32_t target_bitrate_kbps; + }; + + TargetBitrate(); + TargetBitrate(const TargetBitrate&); + TargetBitrate& operator=(const TargetBitrate&); + ~TargetBitrate(); + + void AddTargetBitrate(uint8_t spatial_layer, + uint8_t temporal_layer, + uint32_t target_bitrate_kbps); + + const std::vector<BitrateItem>& GetTargetBitrates() const; + + void Parse(const uint8_t* block, uint16_t block_length); + + size_t BlockLength() const; + + void Create(uint8_t* buffer) const; + + private: + std::vector<BitrateItem> bitrates_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TARGET_BITRATE_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate_unittest.cc new file mode 100644 index 0000000000..5fec75fe44 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate_unittest.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/target_bitrate.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" +#include "rtc_base/buffer.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +namespace webrtc { +namespace { +using BitrateItem = rtcp::TargetBitrate::BitrateItem; +using rtcp::TargetBitrate; +using test::ParseSinglePacket; + +constexpr uint32_t kSsrc = 0x12345678; + +// clang-format off +const uint8_t kPacket[] = { TargetBitrate::kBlockType, // Block ID. + 0x00, // Reserved. + 0x00, 0x04, // Length = 4 words. + 0x00, 0x01, 0x02, 0x03, // S0T0 0x010203 kbps. + 0x01, 0x02, 0x03, 0x04, // S0T1 0x020304 kbps. + 0x10, 0x03, 0x04, 0x05, // S1T0 0x030405 kbps. + 0x11, 0x04, 0x05, 0x06 }; // S1T1 0x040506 kbps. +constexpr size_t kPacketLengthBlocks = ((sizeof(kPacket) + 3) / 4) - 1; +// clang-format on + +void ExpectBirateItemEquals(const BitrateItem& expected, + const BitrateItem& actual) { + EXPECT_EQ(expected.spatial_layer, actual.spatial_layer); + EXPECT_EQ(expected.temporal_layer, actual.temporal_layer); + EXPECT_EQ(expected.target_bitrate_kbps, actual.target_bitrate_kbps); +} + +void CheckBitrateItems(const std::vector<BitrateItem>& bitrates) { + EXPECT_EQ(4U, bitrates.size()); + ExpectBirateItemEquals(BitrateItem(0, 0, 0x010203), bitrates[0]); + ExpectBirateItemEquals(BitrateItem(0, 1, 0x020304), bitrates[1]); + ExpectBirateItemEquals(BitrateItem(1, 0, 0x030405), bitrates[2]); + ExpectBirateItemEquals(BitrateItem(1, 1, 0x040506), bitrates[3]); +} + +} // namespace + +TEST(TargetBitrateTest, Parse) { + TargetBitrate target_bitrate; + target_bitrate.Parse(kPacket, kPacketLengthBlocks); + CheckBitrateItems(target_bitrate.GetTargetBitrates()); +} + +TEST(TargetBitrateTest, FullPacket) { + const size_t kXRHeaderSize = 8; // RTCP header (4) + SSRC (4). + const size_t kTotalSize = kXRHeaderSize + sizeof(kPacket); + uint8_t kRtcpPacket[kTotalSize] = {2 << 6, 207, 0x00, (kTotalSize / 4) - 1, + 0x12, 0x34, 0x56, 0x78}; // SSRC. + memcpy(&kRtcpPacket[kXRHeaderSize], kPacket, sizeof(kPacket)); + rtcp::ExtendedReports xr; + EXPECT_TRUE(ParseSinglePacket(kRtcpPacket, &xr)); + EXPECT_EQ(kSsrc, xr.sender_ssrc()); + const rtc::Optional<TargetBitrate>& target_bitrate = xr.target_bitrate(); + ASSERT_TRUE(static_cast<bool>(target_bitrate)); + CheckBitrateItems(target_bitrate->GetTargetBitrates()); +} + +TEST(TargetBitrateTest, Create) { + TargetBitrate target_bitrate; + target_bitrate.AddTargetBitrate(0, 0, 0x010203); + target_bitrate.AddTargetBitrate(0, 1, 0x020304); + target_bitrate.AddTargetBitrate(1, 0, 0x030405); + target_bitrate.AddTargetBitrate(1, 1, 0x040506); + + uint8_t buffer[sizeof(kPacket)] = {}; + ASSERT_EQ(sizeof(kPacket), target_bitrate.BlockLength()); + target_bitrate.Create(buffer); + + EXPECT_EQ(0, memcmp(kPacket, buffer, sizeof(kPacket))); +} + +TEST(TargetBitrateTest, ParseNullBitratePacket) { + const uint8_t kNullPacket[] = {TargetBitrate::kBlockType, 0x00, 0x00, 0x00}; + TargetBitrate target_bitrate; + target_bitrate.Parse(kNullPacket, 0); + EXPECT_TRUE(target_bitrate.GetTargetBitrates().empty()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc new file mode 100644 index 0000000000..810e1e267a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/tmmb_item.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +TmmbItem::TmmbItem(uint32_t ssrc, uint64_t bitrate_bps, uint16_t overhead) + : ssrc_(ssrc), bitrate_bps_(bitrate_bps), packet_overhead_(overhead) { + RTC_DCHECK_LE(overhead, 0x1ffu); +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | MxTBR Exp | MxTBR Mantissa |Measured Overhead| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +bool TmmbItem::Parse(const uint8_t* buffer) { + ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[0]); + // Read 4 bytes into 1 block. + uint32_t compact = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]); + // Split 1 block into 3 components. + uint8_t exponent = compact >> 26; // 6 bits. + uint64_t mantissa = (compact >> 9) & 0x1ffff; // 17 bits. + uint16_t overhead = compact & 0x1ff; // 9 bits. + // Combine 3 components into 2 values. + bitrate_bps_ = (mantissa << exponent); + + bool shift_overflow = (bitrate_bps_ >> exponent) != mantissa; + if (shift_overflow) { + RTC_LOG(LS_ERROR) << "Invalid tmmb bitrate value : " << mantissa << "*2^" + << static_cast<int>(exponent); + return false; + } + packet_overhead_ = overhead; + return true; +} + +void TmmbItem::Create(uint8_t* buffer) const { + constexpr uint64_t kMaxMantissa = 0x1ffff; // 17 bits. + uint64_t mantissa = bitrate_bps_; + uint32_t exponent = 0; + while (mantissa > kMaxMantissa) { + mantissa >>= 1; + ++exponent; + } + + ByteWriter<uint32_t>::WriteBigEndian(&buffer[0], ssrc_); + uint32_t compact = (exponent << 26) | (mantissa << 9) | packet_overhead_; + ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], compact); +} + +void TmmbItem::set_packet_overhead(uint16_t overhead) { + RTC_DCHECK_LE(overhead, 0x1ffu); + packet_overhead_ = overhead; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h new file mode 100644 index 0000000000..7185976fe0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_TMMB_ITEM_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMB_ITEM_H_ + +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +// RFC5104, Section 3.5.4 +// Temporary Maximum Media Stream Bitrate Request/Notification. +// Used both by TMMBR and TMMBN rtcp packets. +class TmmbItem { + public: + static const size_t kLength = 8; + + TmmbItem() : ssrc_(0), bitrate_bps_(0), packet_overhead_(0) {} + TmmbItem(uint32_t ssrc, uint64_t bitrate_bps, uint16_t overhead); + + bool Parse(const uint8_t* buffer); + void Create(uint8_t* buffer) const; + + void set_ssrc(uint32_t ssrc) { ssrc_ = ssrc; } + void set_bitrate_bps(uint64_t bitrate_bps) { bitrate_bps_ = bitrate_bps; } + void set_packet_overhead(uint16_t overhead); + + uint32_t ssrc() const { return ssrc_; } + uint64_t bitrate_bps() const { return bitrate_bps_; } + uint16_t packet_overhead() const { return packet_overhead_; } + + private: + // Media stream id. + uint32_t ssrc_; + // Maximum total media bit rate that the media receiver is + // currently prepared to accept for this media stream. + uint64_t bitrate_bps_; + // Per-packet overhead that the media receiver has observed + // for this media stream at its chosen reference protocol layer. + uint16_t packet_overhead_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMB_ITEM_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc new file mode 100644 index 0000000000..6205dad6b7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/tmmbn.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Tmmbn::kFeedbackMessageType; +// RFC 4585: Feedback format. +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of media source (unused) = 0 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : Feedback Control Information (FCI) : +// : : +// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104). +// The Feedback Control Information (FCI) consists of zero, one, or more +// TMMBN FCI entries. +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | MxTBR Exp | MxTBR Mantissa |Measured Overhead| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Tmmbn::Tmmbn() = default; + +Tmmbn::~Tmmbn() = default; + +bool Tmmbn::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + + if (packet.payload_size_bytes() < kCommonFeedbackLength) { + RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes() + << " is too small for TMMBN."; + return false; + } + size_t items_size_bytes = packet.payload_size_bytes() - kCommonFeedbackLength; + if (items_size_bytes % TmmbItem::kLength != 0) { + RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes() + << " is not valid for TMMBN."; + return false; + } + ParseCommonFeedback(packet.payload()); + const uint8_t* next_item = packet.payload() + kCommonFeedbackLength; + + size_t number_of_items = items_size_bytes / TmmbItem::kLength; + items_.resize(number_of_items); + for (TmmbItem& item : items_) { + if (!item.Parse(next_item)) + return false; + next_item += TmmbItem::kLength; + } + return true; +} + +void Tmmbn::AddTmmbr(const TmmbItem& item) { + items_.push_back(item); +} + +size_t Tmmbn::BlockLength() const { + return kHeaderLength + kCommonFeedbackLength + + TmmbItem::kLength * items_.size(); +} + +bool Tmmbn::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, + index); + RTC_DCHECK_EQ(0, Rtpfb::media_ssrc()); + CreateCommonFeedback(packet + *index); + *index += kCommonFeedbackLength; + for (const TmmbItem& item : items_) { + item.Create(packet + *index); + *index += TmmbItem::kLength; + } + RTC_CHECK_EQ(index_end, *index); + return true; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h new file mode 100644 index 0000000000..8c3b8348b0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +// Temporary Maximum Media Stream Bit Rate Notification (TMMBN). +// RFC 5104, Section 4.2.2. +class Tmmbn : public Rtpfb { + public: + static constexpr uint8_t kFeedbackMessageType = 4; + + Tmmbn(); + ~Tmmbn() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void AddTmmbr(const TmmbItem& item); + + const std::vector<TmmbItem>& items() const { return items_; } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + // Media ssrc is unused, shadow base class setter and getter. + void SetMediaSsrc(uint32_t ssrc); + uint32_t media_ssrc() const; + + std::vector<TmmbItem> items_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc new file mode 100644 index 0000000000..5a85d8a7bb --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/tmmbn.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAreArray; +using testing::IsEmpty; +using testing::make_tuple; +using webrtc::rtcp::TmmbItem; +using webrtc::rtcp::Tmmbn; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrc = 0x23456789; +const uint32_t kBitrateBps = 312000; +const uint16_t kOverhead = 0x1fe; +const uint8_t kPacket[] = {0x84, 205, 0x00, 0x04, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, + 0x23, 0x45, 0x67, 0x89, + 0x0a, 0x61, 0x61, 0xfe}; +} // namespace + +TEST(RtcpPacketTmmbnTest, Create) { + Tmmbn tmmbn; + tmmbn.SetSenderSsrc(kSenderSsrc); + tmmbn.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead)); + + rtc::Buffer packet = tmmbn.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketTmmbnTest, Parse) { + Tmmbn tmmbn; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &tmmbn)); + + const Tmmbn& parsed = tmmbn; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + ASSERT_EQ(1u, parsed.items().size()); + EXPECT_EQ(kRemoteSsrc, parsed.items().front().ssrc()); + EXPECT_EQ(kBitrateBps, parsed.items().front().bitrate_bps()); + EXPECT_EQ(kOverhead, parsed.items().front().packet_overhead()); +} + +TEST(RtcpPacketTmmbnTest, CreateAndParseWithoutItems) { + Tmmbn tmmbn; + tmmbn.SetSenderSsrc(kSenderSsrc); + + rtc::Buffer packet = tmmbn.Build(); + Tmmbn parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_THAT(parsed.items(), IsEmpty()); +} + +TEST(RtcpPacketTmmbnTest, CreateAndParseWithTwoItems) { + Tmmbn tmmbn; + tmmbn.SetSenderSsrc(kSenderSsrc); + tmmbn.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead)); + tmmbn.AddTmmbr(TmmbItem(kRemoteSsrc + 1, 4 * kBitrateBps, 40)); + + rtc::Buffer packet = tmmbn.Build(); + Tmmbn parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(2u, parsed.items().size()); + EXPECT_EQ(kRemoteSsrc, parsed.items()[0].ssrc()); + EXPECT_EQ(kBitrateBps, parsed.items()[0].bitrate_bps()); + EXPECT_EQ(kOverhead, parsed.items()[0].packet_overhead()); + EXPECT_EQ(kRemoteSsrc + 1, parsed.items()[1].ssrc()); + EXPECT_EQ(4 * kBitrateBps, parsed.items()[1].bitrate_bps()); + EXPECT_EQ(40U, parsed.items()[1].packet_overhead()); +} + +TEST(RtcpPacketTmmbnTest, ParseFailsOnTooSmallPacket) { + const uint8_t kSmallPacket[] = {0x84, 205, 0x00, 0x01, + 0x12, 0x34, 0x56, 0x78}; + Tmmbn tmmbn; + EXPECT_FALSE(test::ParseSinglePacket(kSmallPacket, &tmmbn)); +} + +TEST(RtcpPacketTmmbnTest, ParseFailsOnUnAlignedPacket) { + const uint8_t kUnalignedPacket[] = {0x84, 205, 0x00, 0x03, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, + 0x23, 0x45, 0x67, 0x89}; + + Tmmbn tmmbn; + EXPECT_FALSE(test::ParseSinglePacket(kUnalignedPacket, &tmmbn)); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc new file mode 100644 index 0000000000..34f31029b6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/tmmbr.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +constexpr uint8_t Tmmbr::kFeedbackMessageType; +// RFC 4585: Feedback format. +// Common packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT | PT | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of media source (unused) = 0 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : Feedback Control Information (FCI) : +// : : +// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104). +// The Feedback Control Information (FCI) for the TMMBR +// consists of one or more FCI entries. +// FCI: +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | MxTBR Exp | MxTBR Mantissa |Measured Overhead| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Tmmbr::Tmmbr() = default; + +Tmmbr::~Tmmbr() = default; + +bool Tmmbr::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + + if (packet.payload_size_bytes() < kCommonFeedbackLength + TmmbItem::kLength) { + RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes() + << " is too small for a TMMBR."; + return false; + } + size_t items_size_bytes = packet.payload_size_bytes() - kCommonFeedbackLength; + if (items_size_bytes % TmmbItem::kLength != 0) { + RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes() + << " is not valid for a TMMBR."; + return false; + } + ParseCommonFeedback(packet.payload()); + + const uint8_t* next_item = packet.payload() + kCommonFeedbackLength; + size_t number_of_items = items_size_bytes / TmmbItem::kLength; + items_.resize(number_of_items); + for (TmmbItem& item : items_) { + if (!item.Parse(next_item)) + return false; + next_item += TmmbItem::kLength; + } + return true; +} + +void Tmmbr::AddTmmbr(const TmmbItem& item) { + items_.push_back(item); +} + +size_t Tmmbr::BlockLength() const { + return kHeaderLength + kCommonFeedbackLength + + TmmbItem::kLength * items_.size(); +} + +bool Tmmbr::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + RTC_DCHECK(!items_.empty()); + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, + index); + RTC_DCHECK_EQ(0, Rtpfb::media_ssrc()); + CreateCommonFeedback(packet + *index); + *index += kCommonFeedbackLength; + for (const TmmbItem& item : items_) { + item.Create(packet + *index); + *index += TmmbItem::kLength; + } + RTC_CHECK_EQ(index_end, *index); + return true; +} +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h new file mode 100644 index 0000000000..9b2eca1869 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_ + +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +// Temporary Maximum Media Stream Bit Rate Request (TMMBR). +// RFC 5104, Section 4.2.1. +class Tmmbr : public Rtpfb { + public: + static constexpr uint8_t kFeedbackMessageType = 3; + + Tmmbr(); + ~Tmmbr() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void AddTmmbr(const TmmbItem& item); + + const std::vector<TmmbItem>& requests() const { return items_; } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + // Media ssrc is unused, shadow base class setter. + void SetMediaSsrc(uint32_t ssrc); + + std::vector<TmmbItem> items_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc new file mode 100644 index 0000000000..d3fe72ac72 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtcp_packet/tmmbr.h" + +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using testing::ElementsAreArray; +using testing::IsEmpty; +using testing::make_tuple; +using webrtc::rtcp::TmmbItem; +using webrtc::rtcp::Tmmbr; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345678; +const uint32_t kRemoteSsrc = 0x23456789; +const uint32_t kBitrateBps = 312000; +const uint16_t kOverhead = 0x1fe; +const uint8_t kPacket[] = {0x83, 205, 0x00, 0x04, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, + 0x23, 0x45, 0x67, 0x89, + 0x0a, 0x61, 0x61, 0xfe}; +} // namespace + +TEST(RtcpPacketTmmbrTest, Create) { + Tmmbr tmmbr; + tmmbr.SetSenderSsrc(kSenderSsrc); + tmmbr.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead)); + + rtc::Buffer packet = tmmbr.Build(); + + EXPECT_THAT(make_tuple(packet.data(), packet.size()), + ElementsAreArray(kPacket)); +} + +TEST(RtcpPacketTmmbrTest, Parse) { + Tmmbr tmmbr; + EXPECT_TRUE(test::ParseSinglePacket(kPacket, &tmmbr)); + const Tmmbr& parsed = tmmbr; + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + ASSERT_EQ(1u, parsed.requests().size()); + EXPECT_EQ(kRemoteSsrc, parsed.requests().front().ssrc()); + EXPECT_EQ(kBitrateBps, parsed.requests().front().bitrate_bps()); + EXPECT_EQ(kOverhead, parsed.requests().front().packet_overhead()); +} + +TEST(RtcpPacketTmmbrTest, CreateAndParseWithTwoEntries) { + Tmmbr tmmbr; + tmmbr.SetSenderSsrc(kSenderSsrc); + tmmbr.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead)); + tmmbr.AddTmmbr(TmmbItem(kRemoteSsrc + 1, 4 * kBitrateBps, kOverhead + 1)); + + rtc::Buffer packet = tmmbr.Build(); + + Tmmbr parsed; + EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed)); + + EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc()); + EXPECT_EQ(2u, parsed.requests().size()); + EXPECT_EQ(kRemoteSsrc, parsed.requests()[0].ssrc()); + EXPECT_EQ(kRemoteSsrc + 1, parsed.requests()[1].ssrc()); +} + +TEST(RtcpPacketTmmbrTest, ParseFailsWithoutItems) { + const uint8_t kZeroItemsPacket[] = {0x83, 205, 0x00, 0x02, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00}; + + Tmmbr tmmbr; + EXPECT_FALSE(test::ParseSinglePacket(kZeroItemsPacket, &tmmbr)); +} + +TEST(RtcpPacketTmmbrTest, ParseFailsOnUnAlignedPacket) { + const uint8_t kUnalignedPacket[] = {0x83, 205, 0x00, 0x05, + 0x12, 0x34, 0x56, 0x78, + 0x00, 0x00, 0x00, 0x00, + 0x23, 0x45, 0x67, 0x89, + 0x0a, 0x61, 0x61, 0xfe, + 0x34, 0x56, 0x78, 0x9a}; + + Tmmbr tmmbr; + EXPECT_FALSE(test::ParseSinglePacket(kUnalignedPacket, &tmmbr)); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc new file mode 100644 index 0000000000..794829c7ff --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc @@ -0,0 +1,645 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" + +#include <algorithm> + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/trace_event.h" + +namespace webrtc { +namespace rtcp { +namespace { +// Header size: +// * 4 bytes Common RTCP Packet Header +// * 8 bytes Common Packet Format for RTCP Feedback Messages +// * 8 bytes FeedbackPacket header +constexpr size_t kTransportFeedbackHeaderSizeBytes = 4 + 8 + 8; +constexpr size_t kChunkSizeBytes = 2; +// TODO(sprang): Add support for dynamic max size for easier fragmentation, +// eg. set it to what's left in the buffer or IP_PACKET_SIZE. +// Size constraint imposed by RTCP common header: 16bit size field interpreted +// as number of four byte words minus the first header word. +constexpr size_t kMaxSizeBytes = (1 << 16) * 4; +// Payload size: +// * 8 bytes Common Packet Format for RTCP Feedback Messages +// * 8 bytes FeedbackPacket header. +// * 2 bytes for one chunk. +constexpr size_t kMinPayloadSizeBytes = 8 + 8 + 2; +constexpr int kBaseScaleFactor = + TransportFeedback::kDeltaScaleFactor * (1 << 8); +constexpr int64_t kTimeWrapPeriodUs = (1ll << 24) * kBaseScaleFactor; + +// Message format +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| FMT=15 | PT=205 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC of packet sender | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | SSRC of media source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | base sequence number | packet status count | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | reference time | fb pkt. count | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | packet chunk | packet chunk | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// . . +// . . +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | packet chunk | recv delta | recv delta | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// . . +// . . +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | recv delta | recv delta | zero padding | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +} // namespace +constexpr uint8_t TransportFeedback::kFeedbackMessageType; +constexpr size_t TransportFeedback::kMaxReportedPackets; + +// Keep delta_sizes that can be encoded into single chunk if it is last chunk. +class TransportFeedback::LastChunk { + public: + using DeltaSize = TransportFeedback::DeltaSize; + + LastChunk(); + + bool Empty() const; + void Clear(); + // Return if delta sizes still can be encoded into single chunk with added + // |delta_size|. + bool CanAdd(DeltaSize delta_size) const; + // Add |delta_size|, assumes |CanAdd(delta_size)|, + void Add(DeltaSize delta_size); + + // Encode chunk as large as possible removing encoded delta sizes. + // Assume CanAdd() == false for some valid delta_size. + uint16_t Emit(); + // Encode all stored delta_sizes into single chunk, pad with 0s if needed. + uint16_t EncodeLast() const; + + // Decode up to |max_size| delta sizes from |chunk|. + void Decode(uint16_t chunk, size_t max_size); + // Appends content of the Lastchunk to |deltas|. + void AppendTo(std::vector<DeltaSize>* deltas) const; + + private: + static constexpr size_t kMaxRunLengthCapacity = 0x1fff; + static constexpr size_t kMaxOneBitCapacity = 14; + static constexpr size_t kMaxTwoBitCapacity = 7; + static constexpr size_t kMaxVectorCapacity = kMaxOneBitCapacity; + static constexpr DeltaSize kLarge = 2; + + uint16_t EncodeOneBit() const; + void DecodeOneBit(uint16_t chunk, size_t max_size); + + uint16_t EncodeTwoBit(size_t size) const; + void DecodeTwoBit(uint16_t chunk, size_t max_size); + + uint16_t EncodeRunLength() const; + void DecodeRunLength(uint16_t chunk, size_t max_size); + + DeltaSize delta_sizes_[kMaxVectorCapacity]; + size_t size_; + bool all_same_; + bool has_large_delta_; +}; +constexpr size_t TransportFeedback::LastChunk::kMaxRunLengthCapacity; +constexpr size_t TransportFeedback::LastChunk::kMaxOneBitCapacity; +constexpr size_t TransportFeedback::LastChunk::kMaxTwoBitCapacity; +constexpr size_t TransportFeedback::LastChunk::kMaxVectorCapacity; + +TransportFeedback::LastChunk::LastChunk() { + Clear(); +} + +bool TransportFeedback::LastChunk::Empty() const { + return size_ == 0; +} + +void TransportFeedback::LastChunk::Clear() { + size_ = 0; + all_same_ = true; + has_large_delta_ = false; +} + +bool TransportFeedback::LastChunk::CanAdd(DeltaSize delta_size) const { + RTC_DCHECK_LE(delta_size, 2); + if (size_ < kMaxTwoBitCapacity) + return true; + if (size_ < kMaxOneBitCapacity && !has_large_delta_ && delta_size != kLarge) + return true; + if (size_ < kMaxRunLengthCapacity && all_same_ && + delta_sizes_[0] == delta_size) + return true; + return false; +} + +void TransportFeedback::LastChunk::Add(DeltaSize delta_size) { + RTC_DCHECK(CanAdd(delta_size)); + if (size_ < kMaxVectorCapacity) + delta_sizes_[size_] = delta_size; + size_++; + all_same_ = all_same_ && delta_size == delta_sizes_[0]; + has_large_delta_ = has_large_delta_ || delta_size == kLarge; +} + +uint16_t TransportFeedback::LastChunk::Emit() { + RTC_DCHECK(!CanAdd(0) || !CanAdd(1) || !CanAdd(2)); + if (all_same_) { + uint16_t chunk = EncodeRunLength(); + Clear(); + return chunk; + } + if (size_ == kMaxOneBitCapacity) { + uint16_t chunk = EncodeOneBit(); + Clear(); + return chunk; + } + RTC_DCHECK_GE(size_, kMaxTwoBitCapacity); + uint16_t chunk = EncodeTwoBit(kMaxTwoBitCapacity); + // Remove |kMaxTwoBitCapacity| encoded delta sizes: + // Shift remaining delta sizes and recalculate all_same_ && has_large_delta_. + size_ -= kMaxTwoBitCapacity; + all_same_ = true; + has_large_delta_ = false; + for (size_t i = 0; i < size_; ++i) { + DeltaSize delta_size = delta_sizes_[kMaxTwoBitCapacity + i]; + delta_sizes_[i] = delta_size; + all_same_ = all_same_ && delta_size == delta_sizes_[0]; + has_large_delta_ = has_large_delta_ || delta_size == kLarge; + } + + return chunk; +} + +uint16_t TransportFeedback::LastChunk::EncodeLast() const { + RTC_DCHECK_GT(size_, 0); + if (all_same_) + return EncodeRunLength(); + if (size_ <= kMaxTwoBitCapacity) + return EncodeTwoBit(size_); + return EncodeOneBit(); +} + +// Appends content of the Lastchunk to |deltas|. +void TransportFeedback::LastChunk::AppendTo( + std::vector<DeltaSize>* deltas) const { + if (all_same_) { + deltas->insert(deltas->end(), size_, delta_sizes_[0]); + } else { + deltas->insert(deltas->end(), delta_sizes_, delta_sizes_ + size_); + } +} + +void TransportFeedback::LastChunk::Decode(uint16_t chunk, size_t max_size) { + if ((chunk & 0x8000) == 0) { + DecodeRunLength(chunk, max_size); + } else if ((chunk & 0x4000) == 0) { + DecodeOneBit(chunk, max_size); + } else { + DecodeTwoBit(chunk, max_size); + } +} + +// One Bit Status Vector Chunk +// +// 0 1 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |T|S| symbol list | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// T = 1 +// S = 0 +// Symbol list = 14 entries where 0 = not received, 1 = received 1-byte delta. +uint16_t TransportFeedback::LastChunk::EncodeOneBit() const { + RTC_DCHECK(!has_large_delta_); + RTC_DCHECK_LE(size_, kMaxOneBitCapacity); + uint16_t chunk = 0x8000; + for (size_t i = 0; i < size_; ++i) + chunk |= delta_sizes_[i] << (kMaxOneBitCapacity - 1 - i); + return chunk; +} + +void TransportFeedback::LastChunk::DecodeOneBit(uint16_t chunk, + size_t max_size) { + RTC_DCHECK_EQ(chunk & 0xc000, 0x8000); + size_ = std::min(kMaxOneBitCapacity, max_size); + has_large_delta_ = false; + all_same_ = false; + for (size_t i = 0; i < size_; ++i) + delta_sizes_[i] = (chunk >> (kMaxOneBitCapacity - 1 - i)) & 0x01; +} + +// Two Bit Status Vector Chunk +// +// 0 1 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |T|S| symbol list | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// T = 1 +// S = 1 +// symbol list = 7 entries of two bits each. +uint16_t TransportFeedback::LastChunk::EncodeTwoBit(size_t size) const { + RTC_DCHECK_LE(size, size_); + uint16_t chunk = 0xc000; + for (size_t i = 0; i < size; ++i) + chunk |= delta_sizes_[i] << 2 * (kMaxTwoBitCapacity - 1 - i); + return chunk; +} + +void TransportFeedback::LastChunk::DecodeTwoBit(uint16_t chunk, + size_t max_size) { + RTC_DCHECK_EQ(chunk & 0xc000, 0xc000); + size_ = std::min(kMaxTwoBitCapacity, max_size); + has_large_delta_ = true; + all_same_ = false; + for (size_t i = 0; i < size_; ++i) + delta_sizes_[i] = (chunk >> 2 * (kMaxTwoBitCapacity - 1 - i)) & 0x03; +} + +// Run Length Status Vector Chunk +// +// 0 1 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |T| S | Run Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// T = 0 +// S = symbol +// Run Length = Unsigned integer denoting the run length of the symbol +uint16_t TransportFeedback::LastChunk::EncodeRunLength() const { + RTC_DCHECK(all_same_); + RTC_DCHECK_LE(size_, kMaxRunLengthCapacity); + return (delta_sizes_[0] << 13) | static_cast<uint16_t>(size_); +} + +void TransportFeedback::LastChunk::DecodeRunLength(uint16_t chunk, + size_t max_count) { + RTC_DCHECK_EQ(chunk & 0x8000, 0); + size_ = std::min<size_t>(chunk & 0x1fff, max_count); + DeltaSize delta_size = (chunk >> 13) & 0x03; + has_large_delta_ = delta_size >= kLarge; + all_same_ = true; + // To make it consistent with Add function, populate delta_sizes_ beyound 1st. + for (size_t i = 0; i < std::min<size_t>(size_, kMaxVectorCapacity); ++i) + delta_sizes_[i] = delta_size; +} + +TransportFeedback::TransportFeedback() + : base_seq_no_(0), + num_seq_no_(0), + base_time_ticks_(0), + feedback_seq_(0), + last_timestamp_us_(0), + last_chunk_(new LastChunk()), + size_bytes_(kTransportFeedbackHeaderSizeBytes) {} + +TransportFeedback::~TransportFeedback() {} + +void TransportFeedback::SetBase(uint16_t base_sequence, + int64_t ref_timestamp_us) { + RTC_DCHECK_EQ(num_seq_no_, 0); + RTC_DCHECK_GE(ref_timestamp_us, 0); + base_seq_no_ = base_sequence; + base_time_ticks_ = (ref_timestamp_us % kTimeWrapPeriodUs) / kBaseScaleFactor; + last_timestamp_us_ = GetBaseTimeUs(); +} + +void TransportFeedback::SetFeedbackSequenceNumber(uint8_t feedback_sequence) { + feedback_seq_ = feedback_sequence; +} + +bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number, + int64_t timestamp_us) { + // Convert to ticks and round. + int64_t delta_full = (timestamp_us - last_timestamp_us_) % kTimeWrapPeriodUs; + if (delta_full > kTimeWrapPeriodUs / 2) + delta_full -= kTimeWrapPeriodUs; + delta_full += + delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2; + delta_full /= kDeltaScaleFactor; + + int16_t delta = static_cast<int16_t>(delta_full); + // If larger than 16bit signed, we can't represent it - need new fb packet. + if (delta != delta_full) { + RTC_LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )"; + return false; + } + + uint16_t next_seq_no = base_seq_no_ + num_seq_no_; + if (sequence_number != next_seq_no) { + uint16_t last_seq_no = next_seq_no - 1; + if (!IsNewerSequenceNumber(sequence_number, last_seq_no)) + return false; + for (; next_seq_no != sequence_number; ++next_seq_no) + if (!AddDeltaSize(0)) + return false; + } + + DeltaSize delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2; + if (!AddDeltaSize(delta_size)) + return false; + + packets_.emplace_back(sequence_number, delta); + last_timestamp_us_ += delta * kDeltaScaleFactor; + size_bytes_ += delta_size; + return true; +} + +const std::vector<TransportFeedback::ReceivedPacket>& +TransportFeedback::GetReceivedPackets() const { + return packets_; +} + +uint16_t TransportFeedback::GetBaseSequence() const { + return base_seq_no_; +} + +int64_t TransportFeedback::GetBaseTimeUs() const { + return static_cast<int64_t>(base_time_ticks_) * kBaseScaleFactor; +} + +// De-serialize packet. +bool TransportFeedback::Parse(const CommonHeader& packet) { + RTC_DCHECK_EQ(packet.type(), kPacketType); + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType); + TRACE_EVENT0("webrtc", "TransportFeedback::Parse"); + + if (packet.payload_size_bytes() < kMinPayloadSizeBytes) { + RTC_LOG(LS_WARNING) << "Buffer too small (" << packet.payload_size_bytes() + << " bytes) to fit a " + "FeedbackPacket. Minimum size = " + << kMinPayloadSizeBytes; + return false; + } + + const uint8_t* const payload = packet.payload(); + ParseCommonFeedback(payload); + + base_seq_no_ = ByteReader<uint16_t>::ReadBigEndian(&payload[8]); + uint16_t status_count = ByteReader<uint16_t>::ReadBigEndian(&payload[10]); + base_time_ticks_ = ByteReader<int32_t, 3>::ReadBigEndian(&payload[12]); + feedback_seq_ = payload[15]; + Clear(); + size_t index = 16; + const size_t end_index = packet.payload_size_bytes(); + + if (status_count == 0) { + RTC_LOG(LS_WARNING) << "Empty feedback messages not allowed."; + return false; + } + + std::vector<uint8_t> delta_sizes; + delta_sizes.reserve(status_count); + while (delta_sizes.size() < status_count) { + if (index + kChunkSizeBytes > end_index) { + RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet."; + Clear(); + return false; + } + + uint16_t chunk = ByteReader<uint16_t>::ReadBigEndian(&payload[index]); + index += kChunkSizeBytes; + encoded_chunks_.push_back(chunk); + last_chunk_->Decode(chunk, status_count - delta_sizes.size()); + last_chunk_->AppendTo(&delta_sizes); + } + // Last chunk is stored in the |last_chunk_|. + encoded_chunks_.pop_back(); + RTC_DCHECK_EQ(delta_sizes.size(), status_count); + num_seq_no_ = status_count; + + uint16_t seq_no = base_seq_no_; + for (size_t delta_size : delta_sizes) { + if (index + delta_size > end_index) { + RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet."; + Clear(); + return false; + } + switch (delta_size) { + case 0: + break; + case 1: { + int16_t delta = payload[index]; + packets_.emplace_back(seq_no, delta); + last_timestamp_us_ += delta * kDeltaScaleFactor; + index += delta_size; + break; + } + case 2: { + int16_t delta = ByteReader<int16_t>::ReadBigEndian(&payload[index]); + packets_.emplace_back(seq_no, delta); + last_timestamp_us_ += delta * kDeltaScaleFactor; + index += delta_size; + break; + } + case 3: + Clear(); + RTC_LOG(LS_WARNING) << "Invalid delta_size for seq_no " << seq_no; + return false; + default: + RTC_NOTREACHED(); + break; + } + ++seq_no; + } + size_bytes_ = RtcpPacket::kHeaderLength + index; + RTC_DCHECK_LE(index, end_index); + return true; +} + +std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom( + const uint8_t* buffer, + size_t length) { + CommonHeader header; + if (!header.Parse(buffer, length)) + return nullptr; + if (header.type() != kPacketType || header.fmt() != kFeedbackMessageType) + return nullptr; + std::unique_ptr<TransportFeedback> parsed(new TransportFeedback); + if (!parsed->Parse(header)) + return nullptr; + return parsed; +} + +bool TransportFeedback::IsConsistent() const { + size_t packet_size = kTransportFeedbackHeaderSizeBytes; + std::vector<DeltaSize> delta_sizes; + LastChunk chunk_decoder; + for (uint16_t chunk : encoded_chunks_) { + chunk_decoder.Decode(chunk, kMaxReportedPackets); + chunk_decoder.AppendTo(&delta_sizes); + packet_size += kChunkSizeBytes; + } + if (!last_chunk_->Empty()) { + last_chunk_->AppendTo(&delta_sizes); + packet_size += kChunkSizeBytes; + } + if (num_seq_no_ != delta_sizes.size()) { + RTC_LOG(LS_ERROR) << delta_sizes.size() << " packets encoded. Expected " + << num_seq_no_; + return false; + } + int64_t timestamp_us = base_time_ticks_ * kBaseScaleFactor; + auto packet_it = packets_.begin(); + uint16_t seq_no = base_seq_no_; + for (DeltaSize delta_size : delta_sizes) { + if (delta_size > 0) { + if (packet_it == packets_.end()) { + RTC_LOG(LS_ERROR) << "Failed to find delta for seq_no " << seq_no; + return false; + } + if (packet_it->sequence_number() != seq_no) { + RTC_LOG(LS_ERROR) << "Expected to find delta for seq_no " << seq_no + << ". Next delta is for " + << packet_it->sequence_number(); + return false; + } + if (delta_size == 1 && + (packet_it->delta_ticks() < 0 || packet_it->delta_ticks() > 0xff)) { + RTC_LOG(LS_ERROR) << "Delta " << packet_it->delta_ticks() + << " for seq_no " << seq_no + << " doesn't fit into one byte"; + return false; + } + timestamp_us += packet_it->delta_us(); + ++packet_it; + } + packet_size += delta_size; + ++seq_no; + } + if (packet_it != packets_.end()) { + RTC_LOG(LS_ERROR) << "Unencoded delta for seq_no " + << packet_it->sequence_number(); + return false; + } + if (timestamp_us != last_timestamp_us_) { + RTC_LOG(LS_ERROR) << "Last timestamp mismatch. Calculated: " << timestamp_us + << ". Saved: " << last_timestamp_us_; + return false; + } + if (size_bytes_ != packet_size) { + RTC_LOG(LS_ERROR) << "Rtcp packet size mismatch. Calculated: " + << packet_size << ". Saved: " << size_bytes_; + return false; + } + return true; +} + +size_t TransportFeedback::BlockLength() const { + // Round size_bytes_ up to multiple of 32bits. + return (size_bytes_ + 3) & (~static_cast<size_t>(3)); +} + +// Serialize packet. +bool TransportFeedback::Create(uint8_t* packet, + size_t* position, + size_t max_length, + PacketReadyCallback* callback) const { + if (num_seq_no_ == 0) + return false; + + while (*position + BlockLength() > max_length) { + if (!OnBufferFull(packet, position, callback)) + return false; + } + const size_t position_end = *position + BlockLength(); + + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet, + position); + CreateCommonFeedback(packet + *position); + *position += kCommonFeedbackLength; + + ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_no_); + *position += 2; + + ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], num_seq_no_); + *position += 2; + + ByteWriter<int32_t, 3>::WriteBigEndian(&packet[*position], base_time_ticks_); + *position += 3; + + packet[(*position)++] = feedback_seq_; + + for (uint16_t chunk : encoded_chunks_) { + ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk); + *position += 2; + } + if (!last_chunk_->Empty()) { + uint16_t chunk = last_chunk_->EncodeLast(); + ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk); + *position += 2; + } + + for (const auto& received_packet : packets_) { + int16_t delta = received_packet.delta_ticks(); + if (delta >= 0 && delta <= 0xFF) { + packet[(*position)++] = delta; + } else { + ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta); + *position += 2; + } + } + + while ((*position % 4) != 0) + packet[(*position)++] = 0; + + RTC_DCHECK_EQ(*position, position_end); + return true; +} + +void TransportFeedback::Clear() { + num_seq_no_ = 0; + last_timestamp_us_ = GetBaseTimeUs(); + packets_.clear(); + encoded_chunks_.clear(); + last_chunk_->Clear(); + size_bytes_ = kTransportFeedbackHeaderSizeBytes; +} + +bool TransportFeedback::AddDeltaSize(DeltaSize delta_size) { + if (num_seq_no_ == kMaxReportedPackets) + return false; + size_t add_chunk_size = last_chunk_->Empty() ? kChunkSizeBytes : 0; + if (size_bytes_ + delta_size + add_chunk_size > kMaxSizeBytes) + return false; + + if (last_chunk_->CanAdd(delta_size)) { + size_bytes_ += add_chunk_size; + last_chunk_->Add(delta_size); + ++num_seq_no_; + return true; + } + if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes) + return false; + + encoded_chunks_.push_back(last_chunk_->Emit()); + size_bytes_ += kChunkSizeBytes; + last_chunk_->Add(delta_size); + ++num_seq_no_; + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h new file mode 100644 index 0000000000..a28c573772 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h @@ -0,0 +1,106 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_ + +#include <memory> +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h" + +namespace webrtc { +namespace rtcp { +class CommonHeader; + +class TransportFeedback : public Rtpfb { + public: + class ReceivedPacket { + public: + ReceivedPacket(uint16_t sequence_number, int16_t delta_ticks) + : sequence_number_(sequence_number), delta_ticks_(delta_ticks) {} + ReceivedPacket(const ReceivedPacket&) = default; + ReceivedPacket& operator=(const ReceivedPacket&) = default; + + uint16_t sequence_number() const { return sequence_number_; } + int16_t delta_ticks() const { return delta_ticks_; } + int32_t delta_us() const { return delta_ticks_ * kDeltaScaleFactor; } + + private: + uint16_t sequence_number_; + int16_t delta_ticks_; + }; + // TODO(sprang): IANA reg? + static constexpr uint8_t kFeedbackMessageType = 15; + // Convert to multiples of 0.25ms. + static constexpr int kDeltaScaleFactor = 250; + // Maximum number of packets (including missing) TransportFeedback can report. + static constexpr size_t kMaxReportedPackets = 0xffff; + + TransportFeedback(); + ~TransportFeedback() override; + + void SetBase(uint16_t base_sequence, // Seq# of first packet in this msg. + int64_t ref_timestamp_us); // Reference timestamp for this msg. + void SetFeedbackSequenceNumber(uint8_t feedback_sequence); + // NOTE: This method requires increasing sequence numbers (excepting wraps). + bool AddReceivedPacket(uint16_t sequence_number, int64_t timestamp_us); + const std::vector<ReceivedPacket>& GetReceivedPackets() const; + + uint16_t GetBaseSequence() const; + + // Returns number of packets (including missing) this feedback describes. + size_t GetPacketStatusCount() const { return num_seq_no_; } + + // Get the reference time in microseconds, including any precision loss. + int64_t GetBaseTimeUs() const; + + bool Parse(const CommonHeader& packet); + static std::unique_ptr<TransportFeedback> ParseFrom(const uint8_t* buffer, + size_t length); + // Pre and postcondition for all public methods. Should always return true. + // This function is for tests. + bool IsConsistent() const; + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, + size_t* position, + size_t max_length, + PacketReadyCallback* callback) const override; + + private: + // Size in bytes of a delta time in rtcp packet. + // Valid values are 0 (packet wasn't received), 1 or 2. + using DeltaSize = uint8_t; + // Keeps DeltaSizes that can be encoded into single chunk if it is last chunk. + class LastChunk; + + // Reset packet to consistent empty state. + void Clear(); + + bool AddDeltaSize(DeltaSize delta_size); + + uint16_t base_seq_no_; + uint16_t num_seq_no_; + int32_t base_time_ticks_; + uint8_t feedback_seq_; + + int64_t last_timestamp_us_; + std::vector<ReceivedPacket> packets_; + // All but last encoded packet chunks. + std::vector<uint16_t> encoded_chunks_; + const std::unique_ptr<LastChunk> last_chunk_; + size_t size_bytes_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc new file mode 100644 index 0000000000..1a4cf7874d --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc @@ -0,0 +1,470 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" + +#include <limits> +#include <memory> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::ElementsAreArray; +using rtcp::TransportFeedback; + +static const int kHeaderSize = 20; +static const int kStatusChunkSize = 2; +static const int kSmallDeltaSize = 1; +static const int kLargeDeltaSize = 2; + +static const int64_t kDeltaLimit = 0xFF * TransportFeedback::kDeltaScaleFactor; + +class FeedbackTester { + public: + FeedbackTester() + : expected_size_(kAnySize), + default_delta_(TransportFeedback::kDeltaScaleFactor * 4) {} + + void WithExpectedSize(size_t expected_size) { + expected_size_ = expected_size; + } + + void WithDefaultDelta(int64_t delta) { default_delta_ = delta; } + + void WithInput(const uint16_t received_seq[], + const int64_t received_ts[], + uint16_t length) { + std::unique_ptr<int64_t[]> temp_deltas; + if (received_ts == nullptr) { + temp_deltas.reset(new int64_t[length]); + GenerateDeltas(received_seq, length, temp_deltas.get()); + received_ts = temp_deltas.get(); + } + + expected_seq_.clear(); + expected_deltas_.clear(); + feedback_.reset(new TransportFeedback()); + feedback_->SetBase(received_seq[0], received_ts[0]); + ASSERT_TRUE(feedback_->IsConsistent()); + + int64_t last_time = feedback_->GetBaseTimeUs(); + for (int i = 0; i < length; ++i) { + int64_t time = received_ts[i]; + EXPECT_TRUE(feedback_->AddReceivedPacket(received_seq[i], time)); + + if (last_time != -1) { + int64_t delta = time - last_time; + expected_deltas_.push_back(delta); + } + last_time = time; + } + ASSERT_TRUE(feedback_->IsConsistent()); + expected_seq_.insert(expected_seq_.begin(), &received_seq[0], + &received_seq[length]); + } + + void VerifyPacket() { + ASSERT_TRUE(feedback_->IsConsistent()); + serialized_ = feedback_->Build(); + VerifyInternal(); + feedback_ = TransportFeedback::ParseFrom(serialized_.data(), + serialized_.size()); + ASSERT_TRUE(feedback_->IsConsistent()); + ASSERT_NE(nullptr, feedback_.get()); + VerifyInternal(); + } + + static const size_t kAnySize = static_cast<size_t>(0) - 1; + + private: + void VerifyInternal() { + if (expected_size_ != kAnySize) { + // Round up to whole 32-bit words. + size_t expected_size_words = (expected_size_ + 3) / 4; + size_t expected_size_bytes = expected_size_words * 4; + EXPECT_EQ(expected_size_bytes, serialized_.size()); + } + + std::vector<uint16_t> actual_seq_nos; + std::vector<int64_t> actual_deltas_us; + for (const auto& packet : feedback_->GetReceivedPackets()) { + actual_seq_nos.push_back(packet.sequence_number()); + actual_deltas_us.push_back(packet.delta_us()); + } + EXPECT_THAT(actual_seq_nos, ElementsAreArray(expected_seq_)); + EXPECT_THAT(actual_deltas_us, ElementsAreArray(expected_deltas_)); + } + + void GenerateDeltas(const uint16_t seq[], + const size_t length, + int64_t* deltas) { + uint16_t last_seq = seq[0]; + int64_t offset = 0; + + for (size_t i = 0; i < length; ++i) { + if (seq[i] < last_seq) + offset += 0x10000 * default_delta_; + last_seq = seq[i]; + + deltas[i] = offset + (last_seq * default_delta_); + } + } + + std::vector<uint16_t> expected_seq_; + std::vector<int64_t> expected_deltas_; + size_t expected_size_; + int64_t default_delta_; + std::unique_ptr<TransportFeedback> feedback_; + rtc::Buffer serialized_; +}; + +TEST(RtcpPacketTest, TransportFeedback_OneBitVector) { + const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, nullptr, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_FullOneBitVector) { + const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13, 14}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, nullptr, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapReceived) { + const uint16_t kMax = 0xFFFF; + const uint16_t kReceived[] = {kMax - 2, kMax - 1, kMax, 0, 1, 2}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, nullptr, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapMissing) { + const uint16_t kMax = 0xFFFF; + const uint16_t kReceived[] = {kMax - 2, kMax - 1, 1, 2}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, nullptr, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_TwoBitVector) { + const uint16_t kReceived[] = {1, 2, 6, 7}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + (kLength * kLargeDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor); + test.WithInput(kReceived, nullptr, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_TwoBitVectorFull) { + const uint16_t kReceived[] = {1, 2, 6, 7, 8}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + (2 * kStatusChunkSize) + (kLength * kLargeDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor); + test.WithInput(kReceived, nullptr, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_LargeAndNegativeDeltas) { + const uint16_t kReceived[] = {1, 2, 6, 7, 8}; + const int64_t kReceiveTimes[] = { + 2000, + 1000, + 4000, + 3000, + 3000 + TransportFeedback::kDeltaScaleFactor * (1 << 8)}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + (3 * kLargeDeltaSize) + kSmallDeltaSize; + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, kReceiveTimes, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_MaxRle) { + // Expected chunks created: + // * 1-bit vector chunk (1xreceived + 13xdropped) + // * RLE chunk of max length for dropped symbol + // * 1-bit vector chunk (1xreceived + 13xdropped) + + const size_t kPacketCount = (1 << 13) - 1 + 14; + const uint16_t kReceived[] = {0, kPacketCount}; + const int64_t kReceiveTimes[] = {1000, 2000}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, kReceiveTimes, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_MinRle) { + // Expected chunks created: + // * 1-bit vector chunk (1xreceived + 13xdropped) + // * RLE chunk of length 15 for dropped symbol + // * 1-bit vector chunk (1xreceived + 13xdropped) + + const uint16_t kReceived[] = {0, (14 * 2) + 1}; + const int64_t kReceiveTimes[] = {1000, 2000}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize); + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, kReceiveTimes, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVector) { + const size_t kTwoBitVectorCapacity = 7; + const uint16_t kReceived[] = {0, kTwoBitVectorCapacity - 1}; + const int64_t kReceiveTimes[] = { + 0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + kSmallDeltaSize + kLargeDeltaSize; + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, kReceiveTimes, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSimpleSplit) { + const size_t kTwoBitVectorCapacity = 7; + const uint16_t kReceived[] = {0, kTwoBitVectorCapacity}; + const int64_t kReceiveTimes[] = { + 0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor}; + const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); + const size_t kExpectedSizeBytes = + kHeaderSize + (kStatusChunkSize * 2) + kSmallDeltaSize + kLargeDeltaSize; + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, kReceiveTimes, kLength); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSplit) { + // With received small delta = S, received large delta = L, use input + // SSSSSSSSLSSSSSSSSSSSS. This will cause a 1:2 split at the L. + // After split there will be two symbols in symbol_vec: SL. + + const int64_t kLargeDelta = TransportFeedback::kDeltaScaleFactor * (1 << 8); + const size_t kNumPackets = (3 * 7) + 1; + const size_t kExpectedSizeBytes = kHeaderSize + (kStatusChunkSize * 3) + + (kSmallDeltaSize * (kNumPackets - 1)) + + (kLargeDeltaSize * 1); + + uint16_t kReceived[kNumPackets]; + for (size_t i = 0; i < kNumPackets; ++i) + kReceived[i] = i; + + int64_t kReceiveTimes[kNumPackets]; + kReceiveTimes[0] = 1000; + for (size_t i = 1; i < kNumPackets; ++i) { + int delta = (i == 8) ? kLargeDelta : 1000; + kReceiveTimes[i] = kReceiveTimes[i - 1] + delta; + } + + FeedbackTester test; + test.WithExpectedSize(kExpectedSizeBytes); + test.WithInput(kReceived, kReceiveTimes, kNumPackets); + test.VerifyPacket(); +} + +TEST(RtcpPacketTest, TransportFeedback_Aliasing) { + TransportFeedback feedback; + feedback.SetBase(0, 0); + + const int kSamples = 100; + const int64_t kTooSmallDelta = TransportFeedback::kDeltaScaleFactor / 3; + + for (int i = 0; i < kSamples; ++i) + feedback.AddReceivedPacket(i, i * kTooSmallDelta); + + feedback.Build(); + + int64_t accumulated_delta = 0; + int num_samples = 0; + for (const auto& packet : feedback.GetReceivedPackets()) { + accumulated_delta += packet.delta_us(); + int64_t expected_time = num_samples * kTooSmallDelta; + ++num_samples; + + EXPECT_NEAR(expected_time, accumulated_delta, + TransportFeedback::kDeltaScaleFactor / 2); + } +} + +TEST(RtcpPacketTest, TransportFeedback_Limits) { + // Sequence number wrap above 0x8000. + std::unique_ptr<TransportFeedback> packet(new TransportFeedback()); + packet->SetBase(0, 0); + EXPECT_TRUE(packet->AddReceivedPacket(0x0, 0)); + EXPECT_TRUE(packet->AddReceivedPacket(0x8000, 1000)); + + packet.reset(new TransportFeedback()); + packet->SetBase(0, 0); + EXPECT_TRUE(packet->AddReceivedPacket(0x0, 0)); + EXPECT_FALSE(packet->AddReceivedPacket(0x8000 + 1, 1000)); + + // Packet status count max 0xFFFF. + packet.reset(new TransportFeedback()); + packet->SetBase(0, 0); + EXPECT_TRUE(packet->AddReceivedPacket(0x0, 0)); + EXPECT_TRUE(packet->AddReceivedPacket(0x8000, 1000)); + EXPECT_TRUE(packet->AddReceivedPacket(0xFFFE, 2000)); + EXPECT_FALSE(packet->AddReceivedPacket(0xFFFF, 3000)); + + // Too large delta. + packet.reset(new TransportFeedback()); + packet->SetBase(0, 0); + int64_t kMaxPositiveTimeDelta = std::numeric_limits<int16_t>::max() * + TransportFeedback::kDeltaScaleFactor; + EXPECT_FALSE(packet->AddReceivedPacket( + 1, kMaxPositiveTimeDelta + TransportFeedback::kDeltaScaleFactor)); + EXPECT_TRUE(packet->AddReceivedPacket(1, kMaxPositiveTimeDelta)); + + // Too large negative delta. + packet.reset(new TransportFeedback()); + packet->SetBase(0, 0); + int64_t kMaxNegativeTimeDelta = std::numeric_limits<int16_t>::min() * + TransportFeedback::kDeltaScaleFactor; + EXPECT_FALSE(packet->AddReceivedPacket( + 1, kMaxNegativeTimeDelta - TransportFeedback::kDeltaScaleFactor)); + EXPECT_TRUE(packet->AddReceivedPacket(1, kMaxNegativeTimeDelta)); + + // Base time at maximum value. + int64_t kMaxBaseTime = + static_cast<int64_t>(TransportFeedback::kDeltaScaleFactor) * (1L << 8) * + ((1L << 23) - 1); + packet.reset(new TransportFeedback()); + packet->SetBase(0, kMaxBaseTime); + EXPECT_TRUE(packet->AddReceivedPacket(0, kMaxBaseTime)); + // Serialize and de-serialize (verify 24bit parsing). + rtc::Buffer raw_packet = packet->Build(); + packet = TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size()); + EXPECT_EQ(kMaxBaseTime, packet->GetBaseTimeUs()); + + // Base time above maximum value. + int64_t kTooLargeBaseTime = + kMaxBaseTime + (TransportFeedback::kDeltaScaleFactor * (1L << 8)); + packet.reset(new TransportFeedback()); + packet->SetBase(0, kTooLargeBaseTime); + packet->AddReceivedPacket(0, kTooLargeBaseTime); + raw_packet = packet->Build(); + packet = TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size()); + EXPECT_NE(kTooLargeBaseTime, packet->GetBaseTimeUs()); + + // TODO(sprang): Once we support max length lower than RTCP length limit, + // add back test for max size in bytes. +} + +TEST(RtcpPacketTest, TransportFeedback_Padding) { + const size_t kExpectedSizeBytes = + kHeaderSize + kStatusChunkSize + kSmallDeltaSize; + const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4; + + TransportFeedback feedback; + feedback.SetBase(0, 0); + EXPECT_TRUE(feedback.AddReceivedPacket(0, 0)); + + rtc::Buffer packet = feedback.Build(); + EXPECT_EQ(kExpectedSizeWords * 4, packet.size()); + ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes); + for (size_t i = kExpectedSizeBytes; i < kExpectedSizeWords * 4; ++i) + EXPECT_EQ(0u, packet.data()[i]); + + // Modify packet by adding 4 bytes of padding at the end. Not currently used + // when we're sending, but need to be able to handle it when receiving. + + const int kPaddingBytes = 4; + const size_t kExpectedSizeWithPadding = + (kExpectedSizeWords * 4) + kPaddingBytes; + uint8_t mod_buffer[kExpectedSizeWithPadding]; + memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4); + memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1); + mod_buffer[kExpectedSizeWithPadding - 1] = kPaddingBytes; + const uint8_t padding_flag = 1 << 5; + mod_buffer[0] |= padding_flag; + ByteWriter<uint16_t>::WriteBigEndian( + &mod_buffer[2], ByteReader<uint16_t>::ReadBigEndian(&mod_buffer[2]) + + ((kPaddingBytes + 3) / 4)); + + std::unique_ptr<TransportFeedback> parsed_packet( + TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWithPadding)); + ASSERT_TRUE(parsed_packet.get() != nullptr); + EXPECT_EQ(kExpectedSizeWords * 4, packet.size()); // Padding not included. +} + +TEST(RtcpPacketTest, TransportFeedback_CorrectlySplitsVectorChunks) { + const int kOneBitVectorCapacity = 14; + const int64_t kLargeTimeDelta = + TransportFeedback::kDeltaScaleFactor * (1 << 8); + + // Test that a number of small deltas followed by a large delta results in a + // correct split into multiple chunks, as needed. + + for (int deltas = 0; deltas <= kOneBitVectorCapacity + 1; ++deltas) { + TransportFeedback feedback; + feedback.SetBase(0, 0); + for (int i = 0; i < deltas; ++i) + feedback.AddReceivedPacket(i, i * 1000); + feedback.AddReceivedPacket(deltas, deltas * 1000 + kLargeTimeDelta); + + rtc::Buffer serialized_packet = feedback.Build(); + std::unique_ptr<TransportFeedback> deserialized_packet = + TransportFeedback::ParseFrom(serialized_packet.data(), + serialized_packet.size()); + EXPECT_TRUE(deserialized_packet.get() != nullptr); + } +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc new file mode 100644 index 0000000000..b715b3dedf --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h" + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" + +namespace webrtc { +namespace rtcp { +// VoIP Metrics Report Block (RFC 3611). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | BT=7 | reserved | block length = 8 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | SSRC of source | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | loss rate | discard rate | burst density | gap density | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | burst duration | gap duration | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | round trip delay | end system delay | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 20 | signal level | noise level | RERL | Gmin | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 24 | R factor | ext. R factor | MOS-LQ | MOS-CQ | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 28 | RX config | reserved | JB nominal | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 32 | JB maximum | JB abs max | +// 36 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +VoipMetric::VoipMetric() : ssrc_(0) { + memset(&voip_metric_, 0, sizeof(voip_metric_)); +} + +void VoipMetric::Parse(const uint8_t* buffer) { + RTC_DCHECK(buffer[0] == kBlockType); + // reserved = buffer[1]; + RTC_DCHECK(ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) == kBlockLength); + ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]); + voip_metric_.lossRate = buffer[8]; + voip_metric_.discardRate = buffer[9]; + voip_metric_.burstDensity = buffer[10]; + voip_metric_.gapDensity = buffer[11]; + voip_metric_.burstDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]); + voip_metric_.gapDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[14]); + voip_metric_.roundTripDelay = + ByteReader<uint16_t>::ReadBigEndian(&buffer[16]); + voip_metric_.endSystemDelay = + ByteReader<uint16_t>::ReadBigEndian(&buffer[18]); + voip_metric_.signalLevel = buffer[20]; + voip_metric_.noiseLevel = buffer[21]; + voip_metric_.RERL = buffer[22]; + voip_metric_.Gmin = buffer[23]; + voip_metric_.Rfactor = buffer[24]; + voip_metric_.extRfactor = buffer[25]; + voip_metric_.MOSLQ = buffer[26]; + voip_metric_.MOSCQ = buffer[27]; + voip_metric_.RXconfig = buffer[28]; + // reserved = buffer[29]; + voip_metric_.JBnominal = ByteReader<uint16_t>::ReadBigEndian(&buffer[30]); + voip_metric_.JBmax = ByteReader<uint16_t>::ReadBigEndian(&buffer[32]); + voip_metric_.JBabsMax = ByteReader<uint16_t>::ReadBigEndian(&buffer[34]); +} + +void VoipMetric::Create(uint8_t* buffer) const { + const uint8_t kReserved = 0; + buffer[0] = kBlockType; + buffer[1] = kReserved; + ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockLength); + ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], ssrc_); + buffer[8] = voip_metric_.lossRate; + buffer[9] = voip_metric_.discardRate; + buffer[10] = voip_metric_.burstDensity; + buffer[11] = voip_metric_.gapDensity; + ByteWriter<uint16_t>::WriteBigEndian(&buffer[12], voip_metric_.burstDuration); + ByteWriter<uint16_t>::WriteBigEndian(&buffer[14], voip_metric_.gapDuration); + ByteWriter<uint16_t>::WriteBigEndian(&buffer[16], + voip_metric_.roundTripDelay); + ByteWriter<uint16_t>::WriteBigEndian(&buffer[18], + voip_metric_.endSystemDelay); + buffer[20] = voip_metric_.signalLevel; + buffer[21] = voip_metric_.noiseLevel; + buffer[22] = voip_metric_.RERL; + buffer[23] = voip_metric_.Gmin; + buffer[24] = voip_metric_.Rfactor; + buffer[25] = voip_metric_.extRfactor; + buffer[26] = voip_metric_.MOSLQ; + buffer[27] = voip_metric_.MOSCQ; + buffer[28] = voip_metric_.RXconfig; + buffer[29] = kReserved; + ByteWriter<uint16_t>::WriteBigEndian(&buffer[30], voip_metric_.JBnominal); + ByteWriter<uint16_t>::WriteBigEndian(&buffer[32], voip_metric_.JBmax); + ByteWriter<uint16_t>::WriteBigEndian(&buffer[34], voip_metric_.JBabsMax); +} + +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h new file mode 100644 index 0000000000..135dc45c76 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h @@ -0,0 +1,53 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_ + +#include "modules/include/module_common_types.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { +namespace rtcp { + +class VoipMetric { + public: + static const uint8_t kBlockType = 7; + static const uint16_t kBlockLength = 8; + static const size_t kLength = 4 * (kBlockLength + 1); // 36 + VoipMetric(); + VoipMetric(const VoipMetric&) = default; + ~VoipMetric() {} + + VoipMetric& operator=(const VoipMetric&) = default; + + void Parse(const uint8_t* buffer); + + // Fills buffer with the VoipMetric. + // Consumes VoipMetric::kLength bytes. + void Create(uint8_t* buffer) const; + + void SetMediaSsrc(uint32_t ssrc) { ssrc_ = ssrc; } + void SetVoipMetric(const RTCPVoIPMetric& voip_metric) { + voip_metric_ = voip_metric; + } + + uint32_t ssrc() const { return ssrc_; } + const RTCPVoIPMetric& voip_metric() const { return voip_metric_; } + + private: + uint32_t ssrc_; + RTCPVoIPMetric voip_metric_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc new file mode 100644 index 0000000000..a2fbcc5f75 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h" + +#include "test/gtest.h" + +namespace webrtc { +namespace rtcp { +namespace { + +const uint32_t kRemoteSsrc = 0x23456789; +const uint8_t kBlock[] = {0x07, 0x00, 0x00, 0x08, 0x23, 0x45, 0x67, 0x89, + 0x01, 0x02, 0x03, 0x04, 0x11, 0x12, 0x22, 0x23, + 0x33, 0x34, 0x44, 0x45, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x55, 0x56, + 0x66, 0x67, 0x77, 0x78}; +const size_t kBlockSizeBytes = sizeof(kBlock); +static_assert( + kBlockSizeBytes == VoipMetric::kLength, + "Size of manually created Voip Metric block should match class constant"); + +TEST(RtcpPacketVoipMetricTest, Create) { + uint8_t buffer[VoipMetric::kLength]; + RTCPVoIPMetric metric; + metric.lossRate = 1; + metric.discardRate = 2; + metric.burstDensity = 3; + metric.gapDensity = 4; + metric.burstDuration = 0x1112; + metric.gapDuration = 0x2223; + metric.roundTripDelay = 0x3334; + metric.endSystemDelay = 0x4445; + metric.signalLevel = 5; + metric.noiseLevel = 6; + metric.RERL = 7; + metric.Gmin = 8; + metric.Rfactor = 9; + metric.extRfactor = 10; + metric.MOSLQ = 11; + metric.MOSCQ = 12; + metric.RXconfig = 13; + metric.JBnominal = 0x5556; + metric.JBmax = 0x6667; + metric.JBabsMax = 0x7778; + VoipMetric metric_block; + metric_block.SetMediaSsrc(kRemoteSsrc); + metric_block.SetVoipMetric(metric); + + metric_block.Create(buffer); + EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes)); +} + +TEST(RtcpPacketVoipMetricTest, Parse) { + VoipMetric read_metric; + read_metric.Parse(kBlock); + + // Run checks on const object to ensure all accessors have const modifier. + const VoipMetric& parsed = read_metric; + + EXPECT_EQ(kRemoteSsrc, parsed.ssrc()); + EXPECT_EQ(1, parsed.voip_metric().lossRate); + EXPECT_EQ(2, parsed.voip_metric().discardRate); + EXPECT_EQ(3, parsed.voip_metric().burstDensity); + EXPECT_EQ(4, parsed.voip_metric().gapDensity); + EXPECT_EQ(0x1112, parsed.voip_metric().burstDuration); + EXPECT_EQ(0x2223, parsed.voip_metric().gapDuration); + EXPECT_EQ(0x3334, parsed.voip_metric().roundTripDelay); + EXPECT_EQ(0x4445, parsed.voip_metric().endSystemDelay); + EXPECT_EQ(5, parsed.voip_metric().signalLevel); + EXPECT_EQ(6, parsed.voip_metric().noiseLevel); + EXPECT_EQ(7, parsed.voip_metric().RERL); + EXPECT_EQ(8, parsed.voip_metric().Gmin); + EXPECT_EQ(9, parsed.voip_metric().Rfactor); + EXPECT_EQ(10, parsed.voip_metric().extRfactor); + EXPECT_EQ(11, parsed.voip_metric().MOSLQ); + EXPECT_EQ(12, parsed.voip_metric().MOSCQ); + EXPECT_EQ(13, parsed.voip_metric().RXconfig); + EXPECT_EQ(0x5556, parsed.voip_metric().JBnominal); + EXPECT_EQ(0x6667, parsed.voip_metric().JBmax); + EXPECT_EQ(0x7778, parsed.voip_metric().JBabsMax); +} + +} // namespace +} // namespace rtcp +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc new file mode 100644 index 0000000000..f2a5f2de87 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc @@ -0,0 +1,42 @@ +/* + * 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/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" +#include "test/gmock.h" +#include "test/gtest.h" + +using webrtc::rtcp::ReceiverReport; +using webrtc::rtcp::ReportBlock; + +namespace webrtc { + +const uint32_t kSenderSsrc = 0x12345678; + +TEST(RtcpPacketTest, BuildWithTooSmallBuffer) { + ReportBlock rb; + ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + EXPECT_TRUE(rr.AddReportBlock(rb)); + + const size_t kRrLength = 8; + const size_t kReportBlockLength = 24; + + // No packet. + class Verifier : public rtcp::RtcpPacket::PacketReadyCallback { + void OnPacketReady(uint8_t* data, size_t length) override { + ADD_FAILURE() << "Packet should not fit within max size."; + } + } verifier; + const size_t kBufferSize = kRrLength + kReportBlockLength - 1; + uint8_t buffer[kBufferSize]; + EXPECT_FALSE(rr.BuildExternalBuffer(buffer, kBufferSize, &verifier)); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc new file mode 100644 index 0000000000..09474cccce --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -0,0 +1,1079 @@ +/* + * 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 "modules/rtp_rtcp/source/rtcp_receiver.h" + +#include <string.h> + +#include <limits> +#include <map> +#include <memory> +#include <utility> +#include <vector> + +#include "common_types.h" // NOLINT(build/include) +#include "common_video/include/video_bitrate_allocator.h" +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" +#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtcp_packet/pli.h" +#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h" +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/remb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "modules/rtp_rtcp/source/time_util.h" +#include "modules/rtp_rtcp/source/tmmbr_help.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/trace_event.h" +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { +namespace { + +using rtcp::CommonHeader; +using rtcp::ReportBlock; + +// The number of RTCP time intervals needed to trigger a timeout. +const int kRrTimeoutIntervals = 3; + +const int64_t kMaxWarningLogIntervalMs = 10000; +const int64_t kRtcpMinFrameLengthMs = 17; + +} // namespace + +struct RTCPReceiver::PacketInformation { + uint32_t packet_type_flags = 0; // RTCPPacketTypeFlags bit field. + + uint32_t remote_ssrc = 0; + std::vector<uint16_t> nack_sequence_numbers; + ReportBlockList report_blocks; + int64_t rtt_ms = 0; + uint32_t receiver_estimated_max_bitrate_bps = 0; + std::unique_ptr<rtcp::TransportFeedback> transport_feedback; + rtc::Optional<BitrateAllocation> target_bitrate_allocation; +}; + +// Structure for handing TMMBR and TMMBN rtcp messages (RFC5104, section 3.5.4). +struct RTCPReceiver::TmmbrInformation { + struct TimedTmmbrItem { + rtcp::TmmbItem tmmbr_item; + int64_t last_updated_ms; + }; + + int64_t last_time_received_ms = 0; + + bool ready_for_delete = false; + + std::vector<rtcp::TmmbItem> tmmbn; + std::map<uint32_t, TimedTmmbrItem> tmmbr; +}; + +struct RTCPReceiver::ReportBlockWithRtt { + RTCPReportBlock report_block; + + uint32_t lastReceivedRRNTPsecs = 0; + uint32_t lastReceivedRRNTPfrac = 0; + + int64_t last_rtt_ms = 0; + int64_t min_rtt_ms = 0; + int64_t max_rtt_ms = 0; + int64_t sum_rtt_ms = 0; + size_t num_rtts = 0; +}; + +struct RTCPReceiver::LastFirStatus { + LastFirStatus(int64_t now_ms, uint8_t sequence_number) + : request_ms(now_ms), sequence_number(sequence_number) {} + int64_t request_ms; + uint8_t sequence_number; +}; + +RTCPReceiver::RTCPReceiver( + Clock* clock, + bool receiver_only, + RtcpPacketTypeCounterObserver* packet_type_counter_observer, + RtcpBandwidthObserver* rtcp_bandwidth_observer, + RtcpEventObserver* rtcp_event_observer, + RtcpIntraFrameObserver* rtcp_intra_frame_observer, + TransportFeedbackObserver* transport_feedback_observer, + VideoBitrateAllocationObserver* bitrate_allocation_observer, + ModuleRtpRtcp* owner) + : clock_(clock), + receiver_only_(receiver_only), + rtp_rtcp_(owner), + rtcp_bandwidth_observer_(rtcp_bandwidth_observer), + rtcp_event_observer_(rtcp_event_observer), + rtcp_intra_frame_observer_(rtcp_intra_frame_observer), + transport_feedback_observer_(transport_feedback_observer), + bitrate_allocation_observer_(bitrate_allocation_observer), + main_ssrc_(0), + remote_ssrc_(0), + remote_sender_rtp_time_(0), + remote_sender_packet_count_(0), + remote_sender_octet_count_(0), + xr_rrtr_status_(false), + xr_rr_rtt_ms_(0), + oldest_tmmbr_info_ms_(0), + last_received_rb_ms_(0), + last_increased_sequence_number_ms_(0), + stats_callback_(nullptr), + packet_type_counter_observer_(packet_type_counter_observer), + num_skipped_packets_(0), + last_skipped_packets_warning_ms_(clock->TimeInMilliseconds()) { + RTC_DCHECK(owner); +} + +RTCPReceiver::~RTCPReceiver() {} + +void RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) { + if (packet_size == 0) { + RTC_LOG(LS_WARNING) << "Incoming empty RTCP packet"; + return; + } + + PacketInformation packet_information; + if (!ParseCompoundPacket(packet, packet + packet_size, &packet_information)) + return; + TriggerCallbacksFromRtcpPacket(packet_information); +} + +int64_t RTCPReceiver::LastReceivedReportBlockMs() const { + rtc::CritScope lock(&rtcp_receiver_lock_); + return last_received_rb_ms_; +} + +void RTCPReceiver::SetRemoteSSRC(uint32_t ssrc) { + rtc::CritScope lock(&rtcp_receiver_lock_); + // New SSRC reset old reports. + last_received_sr_ntp_.Reset(); + remote_ssrc_ = ssrc; +} + +uint32_t RTCPReceiver::RemoteSSRC() const { + rtc::CritScope lock(&rtcp_receiver_lock_); + return remote_ssrc_; +} + +void RTCPReceiver::SetSsrcs(uint32_t main_ssrc, + const std::set<uint32_t>& registered_ssrcs) { + rtc::CritScope lock(&rtcp_receiver_lock_); + main_ssrc_ = main_ssrc; + registered_ssrcs_ = registered_ssrcs; +} + +int32_t RTCPReceiver::RTT(uint32_t remote_ssrc, + int64_t* last_rtt_ms, + int64_t* avg_rtt_ms, + int64_t* min_rtt_ms, + int64_t* max_rtt_ms) const { + rtc::CritScope lock(&rtcp_receiver_lock_); + + auto it = received_report_blocks_.find(main_ssrc_); + if (it == received_report_blocks_.end()) + return -1; + + auto it_info = it->second.find(remote_ssrc); + if (it_info == it->second.end()) + return -1; + + const ReportBlockWithRtt* report_block = &it_info->second; + + if (report_block->num_rtts == 0) + return -1; + + if (last_rtt_ms) + *last_rtt_ms = report_block->last_rtt_ms; + + if (avg_rtt_ms) + *avg_rtt_ms = report_block->sum_rtt_ms / report_block->num_rtts; + + if (min_rtt_ms) + *min_rtt_ms = report_block->min_rtt_ms; + + if (max_rtt_ms) + *max_rtt_ms = report_block->max_rtt_ms; + + return 0; +} + +void RTCPReceiver::SetRtcpXrRrtrStatus(bool enable) { + rtc::CritScope lock(&rtcp_receiver_lock_); + xr_rrtr_status_ = enable; +} + +bool RTCPReceiver::GetAndResetXrRrRtt(int64_t* rtt_ms) { + RTC_DCHECK(rtt_ms); + rtc::CritScope lock(&rtcp_receiver_lock_); + if (xr_rr_rtt_ms_ == 0) { + return false; + } + *rtt_ms = xr_rr_rtt_ms_; + xr_rr_rtt_ms_ = 0; + return true; +} + +bool RTCPReceiver::NTP(uint32_t* received_ntp_secs, + uint32_t* received_ntp_frac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp) const { + rtc::CritScope lock(&rtcp_receiver_lock_); + if (!last_received_sr_ntp_.Valid()) + return false; + + // NTP from incoming SenderReport. + if (received_ntp_secs) + *received_ntp_secs = remote_sender_ntp_time_.seconds(); + if (received_ntp_frac) + *received_ntp_frac = remote_sender_ntp_time_.fractions(); + + // Rtp time from incoming SenderReport. + if (rtcp_timestamp) + *rtcp_timestamp = remote_sender_rtp_time_; + + // Local NTP time when we received a RTCP packet with a send block. + if (rtcp_arrival_time_secs) + *rtcp_arrival_time_secs = last_received_sr_ntp_.seconds(); + if (rtcp_arrival_time_frac) + *rtcp_arrival_time_frac = last_received_sr_ntp_.fractions(); + + return true; +} + +void RTCPReceiver::RemoteRTCPSenderInfo(uint32_t* packet_count, + uint32_t* octet_count, + NtpTime* ntp_timestamp) const { + rtc::CritScope lock(&rtcp_receiver_lock_); + *packet_count = remote_sender_packet_count_; + *octet_count = remote_sender_octet_count_; + *ntp_timestamp = remote_sender_ntp_time_; +} + +bool RTCPReceiver::LastReceivedXrReferenceTimeInfo( + rtcp::ReceiveTimeInfo* info) const { + RTC_DCHECK(info); + rtc::CritScope lock(&rtcp_receiver_lock_); + if (!last_received_xr_ntp_.Valid()) + return false; + + info->ssrc = remote_time_info_.ssrc; + info->last_rr = remote_time_info_.last_rr; + + // Get the delay since last received report (RFC 3611). + uint32_t receive_time_ntp = CompactNtp(last_received_xr_ntp_); + uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime()); + + info->delay_since_last_rr = now_ntp - receive_time_ntp; + return true; +} + +// We can get multiple receive reports when we receive the report from a CE. +int32_t RTCPReceiver::StatisticsReceived( + std::vector<RTCPReportBlock>* receive_blocks) const { + RTC_DCHECK(receive_blocks); + rtc::CritScope lock(&rtcp_receiver_lock_); + for (const auto& reports_per_receiver : received_report_blocks_) + for (const auto& report : reports_per_receiver.second) + receive_blocks->push_back(report.second.report_block); + return 0; +} + +bool RTCPReceiver::ParseCompoundPacket(const uint8_t* packet_begin, + const uint8_t* packet_end, + PacketInformation* packet_information) { + rtc::CritScope lock(&rtcp_receiver_lock_); + + CommonHeader rtcp_block; + for (const uint8_t* next_block = packet_begin; next_block != packet_end; + next_block = rtcp_block.NextPacket()) { + ptrdiff_t remaining_blocks_size = packet_end - next_block; + RTC_DCHECK_GT(remaining_blocks_size, 0); + if (!rtcp_block.Parse(next_block, remaining_blocks_size)) { + if (next_block == packet_begin) { + // Failed to parse 1st header, nothing was extracted from this packet. + RTC_LOG(LS_WARNING) << "Incoming invalid RTCP packet"; + return false; + } + ++num_skipped_packets_; + break; + } + + if (packet_type_counter_.first_packet_time_ms == -1) + packet_type_counter_.first_packet_time_ms = clock_->TimeInMilliseconds(); + + switch (rtcp_block.type()) { + case rtcp::SenderReport::kPacketType: + HandleSenderReport(rtcp_block, packet_information); + break; + case rtcp::ReceiverReport::kPacketType: + HandleReceiverReport(rtcp_block, packet_information); + break; + case rtcp::Sdes::kPacketType: + HandleSdes(rtcp_block, packet_information); + break; + case rtcp::ExtendedReports::kPacketType: + HandleXr(rtcp_block, packet_information); + break; + case rtcp::Bye::kPacketType: + HandleBye(rtcp_block); + break; + case rtcp::Rtpfb::kPacketType: + switch (rtcp_block.fmt()) { + case rtcp::Nack::kFeedbackMessageType: + HandleNack(rtcp_block, packet_information); + break; + case rtcp::Tmmbr::kFeedbackMessageType: + HandleTmmbr(rtcp_block, packet_information); + break; + case rtcp::Tmmbn::kFeedbackMessageType: + HandleTmmbn(rtcp_block, packet_information); + break; + case rtcp::RapidResyncRequest::kFeedbackMessageType: + HandleSrReq(rtcp_block, packet_information); + break; + case rtcp::TransportFeedback::kFeedbackMessageType: + HandleTransportFeedback(rtcp_block, packet_information); + break; + default: + ++num_skipped_packets_; + break; + } + break; + case rtcp::Psfb::kPacketType: + switch (rtcp_block.fmt()) { + case rtcp::Pli::kFeedbackMessageType: + HandlePli(rtcp_block, packet_information); + break; + case rtcp::Fir::kFeedbackMessageType: + HandleFir(rtcp_block, packet_information); + break; + case rtcp::Remb::kFeedbackMessageType: + HandlePsfbApp(rtcp_block, packet_information); + break; + default: + ++num_skipped_packets_; + break; + } + break; + default: + ++num_skipped_packets_; + break; + } + } + + if (packet_type_counter_observer_) { + packet_type_counter_observer_->RtcpPacketTypesCounterUpdated( + main_ssrc_, packet_type_counter_); + } + + int64_t now_ms = clock_->TimeInMilliseconds(); + if (now_ms - last_skipped_packets_warning_ms_ >= kMaxWarningLogIntervalMs && + num_skipped_packets_ > 0) { + last_skipped_packets_warning_ms_ = now_ms; + RTC_LOG(LS_WARNING) + << num_skipped_packets_ + << " RTCP blocks were skipped due to being malformed or of " + "unrecognized/unsupported type, during the past " + << (kMaxWarningLogIntervalMs / 1000) << " second period."; + } + + return true; +} + +void RTCPReceiver::HandleSenderReport(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::SenderReport sender_report; + if (!sender_report.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + const uint32_t remote_ssrc = sender_report.sender_ssrc(); + + packet_information->remote_ssrc = remote_ssrc; + + UpdateTmmbrRemoteIsAlive(remote_ssrc); + + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "SR", + "remote_ssrc", remote_ssrc, "ssrc", main_ssrc_); + + // Have I received RTP packets from this party? + if (remote_ssrc_ == remote_ssrc) { + // Only signal that we have received a SR when we accept one. + packet_information->packet_type_flags |= kRtcpSr; + + remote_sender_ntp_time_ = sender_report.ntp(); + remote_sender_rtp_time_ = sender_report.rtp_timestamp(); + last_received_sr_ntp_ = clock_->CurrentNtpTime(); + remote_sender_packet_count_ = sender_report.sender_packet_count(); + remote_sender_octet_count_ = sender_report.sender_octet_count(); + } else { + // We will only store the send report from one source, but + // we will store all the receive blocks. + packet_information->packet_type_flags |= kRtcpRr; + } + + for (const rtcp::ReportBlock& report_block : sender_report.report_blocks()) + HandleReportBlock(report_block, packet_information, remote_ssrc); +} + +void RTCPReceiver::HandleReceiverReport(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::ReceiverReport receiver_report; + if (!receiver_report.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + const uint32_t remote_ssrc = receiver_report.sender_ssrc(); + + packet_information->remote_ssrc = remote_ssrc; + + UpdateTmmbrRemoteIsAlive(remote_ssrc); + + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RR", + "remote_ssrc", remote_ssrc, "ssrc", main_ssrc_); + + packet_information->packet_type_flags |= kRtcpRr; + + for (const ReportBlock& report_block : receiver_report.report_blocks()) + HandleReportBlock(report_block, packet_information, remote_ssrc); +} + +void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block, + PacketInformation* packet_information, + uint32_t remote_ssrc) { + // This will be called once per report block in the RTCP packet. + // We filter out all report blocks that are not for us. + // Each packet has max 31 RR blocks. + // + // We can calc RTT if we send a send report and get a report block back. + + // |report_block.source_ssrc()| is the SSRC identifier of the source to + // which the information in this reception report block pertains. + + // Filter out all report blocks that are not for us. + if (registered_ssrcs_.count(report_block.source_ssrc()) == 0) + return; + + last_received_rb_ms_ = clock_->TimeInMilliseconds(); + + ReportBlockWithRtt* report_block_info = + &received_report_blocks_[report_block.source_ssrc()][remote_ssrc]; + report_block_info->report_block.sender_ssrc = remote_ssrc; + report_block_info->report_block.source_ssrc = report_block.source_ssrc(); + report_block_info->report_block.fraction_lost = report_block.fraction_lost(); + report_block_info->report_block.packets_lost = report_block.cumulative_lost(); + if (report_block.extended_high_seq_num() > + report_block_info->report_block.extended_highest_sequence_number) { + // We have successfully delivered new RTP packets to the remote side after + // the last RR was sent from the remote side. + last_increased_sequence_number_ms_ = clock_->TimeInMilliseconds(); + } + report_block_info->report_block.extended_highest_sequence_number = + report_block.extended_high_seq_num(); + report_block_info->report_block.jitter = report_block.jitter(); + report_block_info->report_block.delay_since_last_sender_report = + report_block.delay_since_last_sr(); + report_block_info->report_block.last_sender_report_timestamp = + report_block.last_sr(); + + 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. + // Receiver rtp_rtcp module is not expected to calculate rtt using + // Sender Reports even if it accidentally can. + if (!receiver_only_ && send_time_ntp != 0) { + uint32_t delay_ntp = report_block.delay_since_last_sr(); + // Local NTP time. + uint32_t receive_time_ntp = CompactNtp(clock_->CurrentNtpTime()); + + // 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); + if (rtt_ms > report_block_info->max_rtt_ms) + report_block_info->max_rtt_ms = rtt_ms; + + if (report_block_info->num_rtts == 0 || + rtt_ms < report_block_info->min_rtt_ms) + report_block_info->min_rtt_ms = rtt_ms; + + report_block_info->last_rtt_ms = rtt_ms; + report_block_info->sum_rtt_ms += rtt_ms; + ++report_block_info->num_rtts; + } + + TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RR_RTT", + report_block.source_ssrc(), rtt_ms); + + packet_information->rtt_ms = rtt_ms; + packet_information->report_blocks.push_back(report_block_info->report_block); +} + +RTCPReceiver::TmmbrInformation* RTCPReceiver::FindOrCreateTmmbrInfo( + uint32_t remote_ssrc) { + // Create or find receive information. + TmmbrInformation* tmmbr_info = &tmmbr_infos_[remote_ssrc]; + // Update that this remote is alive. + tmmbr_info->last_time_received_ms = clock_->TimeInMilliseconds(); + return tmmbr_info; +} + +void RTCPReceiver::UpdateTmmbrRemoteIsAlive(uint32_t remote_ssrc) { + auto tmmbr_it = tmmbr_infos_.find(remote_ssrc); + if (tmmbr_it != tmmbr_infos_.end()) + tmmbr_it->second.last_time_received_ms = clock_->TimeInMilliseconds(); +} + +RTCPReceiver::TmmbrInformation* RTCPReceiver::GetTmmbrInformation( + uint32_t remote_ssrc) { + auto it = tmmbr_infos_.find(remote_ssrc); + if (it == tmmbr_infos_.end()) + return nullptr; + return &it->second; +} + +bool RTCPReceiver::RtcpRrTimeout(int64_t rtcp_interval_ms) { + rtc::CritScope lock(&rtcp_receiver_lock_); + if (last_received_rb_ms_ == 0) + return false; + + int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms; + if (clock_->TimeInMilliseconds() > last_received_rb_ms_ + time_out_ms) { + // Reset the timer to only trigger one log. + last_received_rb_ms_ = 0; + if (rtcp_event_observer_) { + rtcp_event_observer_->OnRtcpTimeout(); + } + return true; + } + return false; +} + +bool RTCPReceiver::RtcpRrSequenceNumberTimeout(int64_t rtcp_interval_ms) { + rtc::CritScope lock(&rtcp_receiver_lock_); + if (last_increased_sequence_number_ms_ == 0) + return false; + + int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms; + if (clock_->TimeInMilliseconds() > + last_increased_sequence_number_ms_ + time_out_ms) { + // Reset the timer to only trigger one log. + last_increased_sequence_number_ms_ = 0; + if (rtcp_event_observer_) { + rtcp_event_observer_->OnRtcpTimeout(); + } + return true; + } + return false; +} + +bool RTCPReceiver::UpdateTmmbrTimers() { + rtc::CritScope lock(&rtcp_receiver_lock_); + + int64_t now_ms = clock_->TimeInMilliseconds(); + // Use audio define since we don't know what interval the remote peer use. + int64_t timeout_ms = now_ms - 5 * RTCP_INTERVAL_AUDIO_MS; + + if (oldest_tmmbr_info_ms_ >= timeout_ms) + return false; + + bool update_bounding_set = false; + oldest_tmmbr_info_ms_ = -1; + for (auto tmmbr_it = tmmbr_infos_.begin(); tmmbr_it != tmmbr_infos_.end();) { + TmmbrInformation* tmmbr_info = &tmmbr_it->second; + if (tmmbr_info->last_time_received_ms > 0) { + if (tmmbr_info->last_time_received_ms < timeout_ms) { + // No rtcp packet for the last 5 regular intervals, reset limitations. + tmmbr_info->tmmbr.clear(); + // Prevent that we call this over and over again. + tmmbr_info->last_time_received_ms = 0; + // Send new TMMBN to all channels using the default codec. + update_bounding_set = true; + } else if (oldest_tmmbr_info_ms_ == -1 || + tmmbr_info->last_time_received_ms < oldest_tmmbr_info_ms_) { + oldest_tmmbr_info_ms_ = tmmbr_info->last_time_received_ms; + } + ++tmmbr_it; + } else if (tmmbr_info->ready_for_delete) { + // When we dont have a last_time_received_ms and the object is marked + // ready_for_delete it's removed from the map. + tmmbr_it = tmmbr_infos_.erase(tmmbr_it); + } else { + ++tmmbr_it; + } + } + return update_bounding_set; +} + +std::vector<rtcp::TmmbItem> RTCPReceiver::BoundingSet(bool* tmmbr_owner) { + rtc::CritScope lock(&rtcp_receiver_lock_); + TmmbrInformation* tmmbr_info = GetTmmbrInformation(remote_ssrc_); + if (!tmmbr_info) + return std::vector<rtcp::TmmbItem>(); + + *tmmbr_owner = TMMBRHelp::IsOwner(tmmbr_info->tmmbn, main_ssrc_); + return tmmbr_info->tmmbn; +} + +void RTCPReceiver::HandleSdes(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::Sdes sdes; + if (!sdes.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + for (const rtcp::Sdes::Chunk& chunk : sdes.chunks()) { + received_cnames_[chunk.ssrc] = chunk.cname; + { + rtc::CritScope lock(&feedbacks_lock_); + if (stats_callback_) + stats_callback_->CNameChanged(chunk.cname.c_str(), chunk.ssrc); + } + } + packet_information->packet_type_flags |= kRtcpSdes; +} + +void RTCPReceiver::HandleNack(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::Nack nack; + if (!nack.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + if (receiver_only_ || main_ssrc_ != nack.media_ssrc()) // Not to us. + return; + + packet_information->nack_sequence_numbers.insert( + packet_information->nack_sequence_numbers.end(), + nack.packet_ids().begin(), nack.packet_ids().end()); + for (uint16_t packet_id : nack.packet_ids()) + nack_stats_.ReportRequest(packet_id); + + if (!nack.packet_ids().empty()) { + packet_information->packet_type_flags |= kRtcpNack; + ++packet_type_counter_.nack_packets; + packet_type_counter_.nack_requests = nack_stats_.requests(); + packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests(); + } +} + +void RTCPReceiver::HandleBye(const CommonHeader& rtcp_block) { + rtcp::Bye bye; + if (!bye.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + if (rtcp_event_observer_) { + rtcp_event_observer_->OnRtcpBye(); + } + + // Clear our lists. + for (auto& reports_per_receiver : received_report_blocks_) + reports_per_receiver.second.erase(bye.sender_ssrc()); + + TmmbrInformation* tmmbr_info = GetTmmbrInformation(bye.sender_ssrc()); + if (tmmbr_info) + tmmbr_info->ready_for_delete = true; + + last_fir_.erase(bye.sender_ssrc()); + received_cnames_.erase(bye.sender_ssrc()); + xr_rr_rtt_ms_ = 0; +} + +void RTCPReceiver::HandleXr(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::ExtendedReports xr; + if (!xr.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + if (xr.rrtr()) + HandleXrReceiveReferenceTime(xr.sender_ssrc(), *xr.rrtr()); + + for (const rtcp::ReceiveTimeInfo& time_info : xr.dlrr().sub_blocks()) + HandleXrDlrrReportBlock(time_info); + + if (xr.target_bitrate()) { + HandleXrTargetBitrate(xr.sender_ssrc(), *xr.target_bitrate(), + packet_information); + } +} + +void RTCPReceiver::HandleXrReceiveReferenceTime(uint32_t sender_ssrc, + const rtcp::Rrtr& rrtr) { + remote_time_info_.ssrc = sender_ssrc; + remote_time_info_.last_rr = CompactNtp(rrtr.ntp()); + last_received_xr_ntp_ = clock_->CurrentNtpTime(); +} + +void RTCPReceiver::HandleXrDlrrReportBlock(const rtcp::ReceiveTimeInfo& rti) { + if (registered_ssrcs_.count(rti.ssrc) == 0) // Not to us. + return; + + // Caller should explicitly enable rtt calculation using extended reports. + if (!xr_rrtr_status_) + return; + + // The send_time and delay_rr fields are in units of 1/2^16 sec. + uint32_t send_time_ntp = rti.last_rr; + // RFC3611, section 4.5, LRR field discription states: + // If no such block has been received, the field is set to zero. + if (send_time_ntp == 0) + return; + + uint32_t delay_ntp = rti.delay_since_last_rr; + 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); +} + +void RTCPReceiver::HandleXrTargetBitrate( + uint32_t ssrc, + const rtcp::TargetBitrate& target_bitrate, + PacketInformation* packet_information) { + if (ssrc != remote_ssrc_) { + return; // Not for us. + } + + BitrateAllocation bitrate_allocation; + for (const auto& item : target_bitrate.GetTargetBitrates()) { + if (item.spatial_layer >= kMaxSpatialLayers || + item.temporal_layer >= kMaxTemporalStreams) { + RTC_LOG(LS_WARNING) + << "Invalid layer in XR target bitrate pack: spatial index " + << item.spatial_layer << ", temporal index " << item.temporal_layer + << ", dropping."; + } else { + bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer, + item.target_bitrate_kbps * 1000); + } + } + packet_information->target_bitrate_allocation.emplace(bitrate_allocation); +} + +void RTCPReceiver::HandlePli(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::Pli pli; + if (!pli.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + if (main_ssrc_ == pli.media_ssrc()) { + TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PLI"); + + ++packet_type_counter_.pli_packets; + // Received a signal that we need to send a new key frame. + packet_information->packet_type_flags |= kRtcpPli; + } +} + +void RTCPReceiver::HandleTmmbr(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::Tmmbr tmmbr; + if (!tmmbr.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + uint32_t sender_ssrc = tmmbr.sender_ssrc(); + if (tmmbr.media_ssrc()) { + // media_ssrc() SHOULD be 0 if same as SenderSSRC. + // In relay mode this is a valid number. + sender_ssrc = tmmbr.media_ssrc(); + } + + for (const rtcp::TmmbItem& request : tmmbr.requests()) { + if (main_ssrc_ != request.ssrc() || request.bitrate_bps() == 0) + continue; + + TmmbrInformation* tmmbr_info = FindOrCreateTmmbrInfo(tmmbr.sender_ssrc()); + auto* entry = &tmmbr_info->tmmbr[sender_ssrc]; + entry->tmmbr_item = rtcp::TmmbItem(sender_ssrc, + request.bitrate_bps(), + request.packet_overhead()); + entry->last_updated_ms = clock_->TimeInMilliseconds(); + + packet_information->packet_type_flags |= kRtcpTmmbr; + break; + } +} + +void RTCPReceiver::HandleTmmbn(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::Tmmbn tmmbn; + if (!tmmbn.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + TmmbrInformation* tmmbr_info = FindOrCreateTmmbrInfo(tmmbn.sender_ssrc()); + + packet_information->packet_type_flags |= kRtcpTmmbn; + + tmmbr_info->tmmbn = tmmbn.items(); +} + +void RTCPReceiver::HandleSrReq(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::RapidResyncRequest sr_req; + if (!sr_req.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + packet_information->packet_type_flags |= kRtcpSrReq; +} + +void RTCPReceiver::HandlePsfbApp(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::Remb remb; + if (remb.Parse(rtcp_block)) { + packet_information->packet_type_flags |= kRtcpRemb; + packet_information->receiver_estimated_max_bitrate_bps = remb.bitrate_bps(); + return; + } + + ++num_skipped_packets_; +} + +void RTCPReceiver::HandleFir(const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + rtcp::Fir fir; + if (!fir.Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + for (const rtcp::Fir::Request& fir_request : fir.requests()) { + // Is it our sender that is requested to generate a new keyframe. + if (main_ssrc_ != fir_request.ssrc) + continue; + + ++packet_type_counter_.fir_packets; + + int64_t now_ms = clock_->TimeInMilliseconds(); + auto inserted = last_fir_.insert(std::make_pair( + fir.sender_ssrc(), LastFirStatus(now_ms, fir_request.seq_nr))); + if (!inserted.second) { // There was already an entry. + LastFirStatus* last_fir = &inserted.first->second; + + // Check if we have reported this FIRSequenceNumber before. + if (fir_request.seq_nr == last_fir->sequence_number) + continue; + + // Sanity: don't go crazy with the callbacks. + if (now_ms - last_fir->request_ms < kRtcpMinFrameLengthMs) + continue; + + last_fir->request_ms = now_ms; + last_fir->sequence_number = fir_request.seq_nr; + } + // Received signal that we need to send a new key frame. + packet_information->packet_type_flags |= kRtcpFir; + } +} + +void RTCPReceiver::HandleTransportFeedback( + const CommonHeader& rtcp_block, + PacketInformation* packet_information) { + std::unique_ptr<rtcp::TransportFeedback> transport_feedback( + new rtcp::TransportFeedback()); + if (!transport_feedback->Parse(rtcp_block)) { + ++num_skipped_packets_; + return; + } + + packet_information->packet_type_flags |= kRtcpTransportFeedback; + packet_information->transport_feedback = std::move(transport_feedback); +} + +void RTCPReceiver::NotifyTmmbrUpdated() { + // Find bounding set. + std::vector<rtcp::TmmbItem> bounding = + TMMBRHelp::FindBoundingSet(TmmbrReceived()); + + if (!bounding.empty() && rtcp_bandwidth_observer_) { + // We have a new bandwidth estimate on this channel. + uint64_t bitrate_bps = TMMBRHelp::CalcMinBitrateBps(bounding); + if (bitrate_bps <= std::numeric_limits<uint32_t>::max()) + rtcp_bandwidth_observer_->OnReceivedEstimatedBitrate(bitrate_bps); + } + + // Send tmmbn to inform remote clients about the new bandwidth. + rtp_rtcp_->SetTmmbn(std::move(bounding)); +} + +void RTCPReceiver::RegisterRtcpStatisticsCallback( + RtcpStatisticsCallback* callback) { + rtc::CritScope cs(&feedbacks_lock_); + stats_callback_ = callback; +} + +RtcpStatisticsCallback* RTCPReceiver::GetRtcpStatisticsCallback() { + rtc::CritScope cs(&feedbacks_lock_); + return stats_callback_; +} + +// Holding no Critical section. +void RTCPReceiver::TriggerCallbacksFromRtcpPacket( + const PacketInformation& packet_information) { + // Process TMMBR and REMB first to avoid multiple callbacks + // to OnNetworkChanged. + if (packet_information.packet_type_flags & kRtcpTmmbr) { + // Might trigger a OnReceivedBandwidthEstimateUpdate. + NotifyTmmbrUpdated(); + } + uint32_t local_ssrc; + std::set<uint32_t> registered_ssrcs; + { + // We don't want to hold this critsect when triggering the callbacks below. + rtc::CritScope lock(&rtcp_receiver_lock_); + local_ssrc = main_ssrc_; + registered_ssrcs = registered_ssrcs_; + } + if (!receiver_only_ && (packet_information.packet_type_flags & kRtcpSrReq)) { + rtp_rtcp_->OnRequestSendReport(); + } + if (!receiver_only_ && (packet_information.packet_type_flags & kRtcpNack)) { + if (!packet_information.nack_sequence_numbers.empty()) { + RTC_LOG(LS_VERBOSE) << "Incoming NACK length: " + << packet_information.nack_sequence_numbers.size(); + rtp_rtcp_->OnReceivedNack(packet_information.nack_sequence_numbers); + } + } + + // We need feedback that we have received a report block(s) so that we + // can generate a new packet in a conference relay scenario, one received + // report can generate several RTCP packets, based on number relayed/mixed + // a send report block should go out to all receivers. + if (rtcp_intra_frame_observer_) { + RTC_DCHECK(!receiver_only_); + if ((packet_information.packet_type_flags & kRtcpPli) || + (packet_information.packet_type_flags & kRtcpFir)) { + if (packet_information.packet_type_flags & kRtcpPli) { + RTC_LOG(LS_VERBOSE) + << "Incoming PLI from SSRC " << packet_information.remote_ssrc; + } else { + RTC_LOG(LS_VERBOSE) + << "Incoming FIR from SSRC " << packet_information.remote_ssrc; + } + rtcp_intra_frame_observer_->OnReceivedIntraFrameRequest(local_ssrc); + } + } + if (rtcp_bandwidth_observer_) { + RTC_DCHECK(!receiver_only_); + if (packet_information.packet_type_flags & kRtcpRemb) { + RTC_LOG(LS_VERBOSE) + << "Incoming REMB: " + << packet_information.receiver_estimated_max_bitrate_bps; + rtcp_bandwidth_observer_->OnReceivedEstimatedBitrate( + packet_information.receiver_estimated_max_bitrate_bps); + } + if ((packet_information.packet_type_flags & kRtcpSr) || + (packet_information.packet_type_flags & kRtcpRr)) { + int64_t now_ms = clock_->TimeInMilliseconds(); + rtcp_bandwidth_observer_->OnReceivedRtcpReceiverReport( + packet_information.report_blocks, packet_information.rtt_ms, now_ms); + } + } + if ((packet_information.packet_type_flags & kRtcpSr) || + (packet_information.packet_type_flags & kRtcpRr)) { + rtp_rtcp_->OnReceivedRtcpReportBlocks(packet_information.report_blocks); + } + + if (transport_feedback_observer_ && + (packet_information.packet_type_flags & kRtcpTransportFeedback)) { + uint32_t media_source_ssrc = + packet_information.transport_feedback->media_ssrc(); + if (media_source_ssrc == local_ssrc || + registered_ssrcs.find(media_source_ssrc) != registered_ssrcs.end()) { + transport_feedback_observer_->OnTransportFeedback( + *packet_information.transport_feedback); + } + } + + if (bitrate_allocation_observer_ && + packet_information.target_bitrate_allocation) { + bitrate_allocation_observer_->OnBitrateAllocationUpdated( + *packet_information.target_bitrate_allocation); + } + + if (!receiver_only_) { + rtc::CritScope cs(&feedbacks_lock_); + if (stats_callback_) { + for (const auto& report_block : packet_information.report_blocks) { + RtcpStatistics stats; + stats.packets_lost = report_block.packets_lost; + stats.extended_highest_sequence_number = + report_block.extended_highest_sequence_number; + stats.fraction_lost = report_block.fraction_lost; + stats.jitter = report_block.jitter; + + stats_callback_->StatisticsUpdated(stats, report_block.source_ssrc); + } + } + } +} + +int32_t RTCPReceiver::CNAME(uint32_t remoteSSRC, + char cName[RTCP_CNAME_SIZE]) const { + RTC_DCHECK(cName); + + rtc::CritScope lock(&rtcp_receiver_lock_); + auto received_cname_it = received_cnames_.find(remoteSSRC); + if (received_cname_it == received_cnames_.end()) + return -1; + + size_t length = received_cname_it->second.copy(cName, RTCP_CNAME_SIZE - 1); + cName[length] = 0; + return 0; +} + +std::vector<rtcp::TmmbItem> RTCPReceiver::TmmbrReceived() { + rtc::CritScope lock(&rtcp_receiver_lock_); + std::vector<rtcp::TmmbItem> candidates; + + int64_t now_ms = clock_->TimeInMilliseconds(); + // Use audio define since we don't know what interval the remote peer use. + int64_t timeout_ms = now_ms - 5 * RTCP_INTERVAL_AUDIO_MS; + + for (auto& kv : tmmbr_infos_) { + for (auto it = kv.second.tmmbr.begin(); it != kv.second.tmmbr.end();) { + if (it->second.last_updated_ms < timeout_ms) { + // Erase timeout entries. + it = kv.second.tmmbr.erase(it); + } else { + candidates.push_back(it->second.tmmbr_item); + ++it; + } + } + } + return candidates; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h new file mode 100644 index 0000000000..4caa7b9132 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h @@ -0,0 +1,280 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ + +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_nack_stats.h" +#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/thread_annotations.h" +#include "system_wrappers/include/ntp_time.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +class VideoBitrateAllocationObserver; +namespace rtcp { +class CommonHeader; +class ReportBlock; +class Rrtr; +class TargetBitrate; +class TmmbItem; +} // namespace rtcp + +class RTCPReceiver { + public: + class ModuleRtpRtcp { + public: + virtual void SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) = 0; + virtual void OnRequestSendReport() = 0; + virtual void OnReceivedNack( + const std::vector<uint16_t>& nack_sequence_numbers) = 0; + virtual void OnReceivedRtcpReportBlocks( + const ReportBlockList& report_blocks) = 0; + + virtual bool GetSendReportMetadata(const uint32_t send_report, + uint64_t *time_of_send, + uint32_t *packet_count, + uint64_t *octet_count) = 0; + + protected: + virtual ~ModuleRtpRtcp() = default; + }; + + RTCPReceiver(Clock* clock, + bool receiver_only, + RtcpPacketTypeCounterObserver* packet_type_counter_observer, + RtcpBandwidthObserver* rtcp_bandwidth_observer, + RtcpEventObserver* rtcp_event_observer, + RtcpIntraFrameObserver* rtcp_intra_frame_observer, + TransportFeedbackObserver* transport_feedback_observer, + VideoBitrateAllocationObserver* bitrate_allocation_observer, + ModuleRtpRtcp* owner); + virtual ~RTCPReceiver(); + + void IncomingPacket(const uint8_t* packet, size_t packet_size); + + int64_t LastReceivedReportBlockMs() const; + + void SetSsrcs(uint32_t main_ssrc, const std::set<uint32_t>& registered_ssrcs); + void SetRemoteSSRC(uint32_t ssrc); + uint32_t RemoteSSRC() const; + + // Get received cname. + int32_t CNAME(uint32_t remote_ssrc, char cname[RTCP_CNAME_SIZE]) const; + + // Get received NTP. + bool NTP(uint32_t* received_ntp_secs, + uint32_t* received_ntp_frac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp) const; + + // Get received sender packet and octet counts + void RemoteRTCPSenderInfo(uint32_t* packet_count, + uint32_t* octet_count, + NtpTime* ntp_timestamp) const; + + bool LastReceivedXrReferenceTimeInfo(rtcp::ReceiveTimeInfo* info) const; + + // Get rtt. + int32_t RTT(uint32_t remote_ssrc, + int64_t* last_rtt_ms, + int64_t* avg_rtt_ms, + int64_t* min_rtt_ms, + int64_t* max_rtt_ms) const; + + void SetRtcpXrRrtrStatus(bool enable); + bool GetAndResetXrRrRtt(int64_t* rtt_ms); + + // Get statistics. + int32_t StatisticsReceived(std::vector<RTCPReportBlock>* receiveBlocks) const; + + // Returns true if we haven't received an RTCP RR for several RTCP + // intervals, but only triggers true once. + bool RtcpRrTimeout(int64_t rtcp_interval_ms); + + // Returns true if we haven't received an RTCP RR telling the receive side + // has not received RTP packets for too long, i.e. extended highest sequence + // number hasn't increased for several RTCP intervals. The function only + // returns true once until a new RR is received. + bool RtcpRrSequenceNumberTimeout(int64_t rtcp_interval_ms); + + std::vector<rtcp::TmmbItem> TmmbrReceived(); + // Return true if new bandwidth should be set. + bool UpdateTmmbrTimers(); + std::vector<rtcp::TmmbItem> BoundingSet(bool* tmmbr_owner); + // Set new bandwidth and notify remote clients about it. + void NotifyTmmbrUpdated(); + + void RegisterRtcpStatisticsCallback(RtcpStatisticsCallback* callback); + RtcpStatisticsCallback* GetRtcpStatisticsCallback(); + + private: + struct PacketInformation; + struct TmmbrInformation; + struct ReportBlockWithRtt; + struct LastFirStatus; + // RTCP report blocks mapped by remote SSRC. + using ReportBlockInfoMap = std::map<uint32_t, ReportBlockWithRtt>; + // RTCP report blocks map mapped by source SSRC. + using ReportBlockMap = std::map<uint32_t, ReportBlockInfoMap>; + + bool ParseCompoundPacket(const uint8_t* packet_begin, + const uint8_t* packet_end, + PacketInformation* packet_information); + + void TriggerCallbacksFromRtcpPacket( + const PacketInformation& packet_information); + + TmmbrInformation* FindOrCreateTmmbrInfo(uint32_t remote_ssrc) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + // Update TmmbrInformation (if present) is alive. + void UpdateTmmbrRemoteIsAlive(uint32_t remote_ssrc) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + TmmbrInformation* GetTmmbrInformation(uint32_t remote_ssrc) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleSenderReport(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleReceiverReport(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleReportBlock(const rtcp::ReportBlock& report_block, + PacketInformation* packet_information, + uint32_t remote_ssrc) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleSdes(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleXr(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleXrReceiveReferenceTime(uint32_t sender_ssrc, + const rtcp::Rrtr& rrtr) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleXrDlrrReportBlock(const rtcp::ReceiveTimeInfo& rti) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleXrTargetBitrate(uint32_t ssrc, + const rtcp::TargetBitrate& target_bitrate, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleNack(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleBye(const rtcp::CommonHeader& rtcp_block) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandlePli(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandlePsfbApp(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleTmmbr(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleTmmbn(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleSrReq(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleFir(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + void HandleTransportFeedback(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + + Clock* const clock_; + const bool receiver_only_; + ModuleRtpRtcp* const rtp_rtcp_; + + rtc::CriticalSection feedbacks_lock_; + RtcpBandwidthObserver* const rtcp_bandwidth_observer_; + RtcpEventObserver* const rtcp_event_observer_; + RtcpIntraFrameObserver* const rtcp_intra_frame_observer_; + TransportFeedbackObserver* const transport_feedback_observer_; + VideoBitrateAllocationObserver* const bitrate_allocation_observer_; + + rtc::CriticalSection rtcp_receiver_lock_; + uint32_t main_ssrc_ RTC_GUARDED_BY(rtcp_receiver_lock_); + uint32_t remote_ssrc_ RTC_GUARDED_BY(rtcp_receiver_lock_); + std::set<uint32_t> registered_ssrcs_ RTC_GUARDED_BY(rtcp_receiver_lock_); + + // Received sender report. + NtpTime remote_sender_ntp_time_ RTC_GUARDED_BY(rtcp_receiver_lock_); + uint32_t remote_sender_rtp_time_ RTC_GUARDED_BY(rtcp_receiver_lock_); + uint32_t remote_sender_packet_count_ RTC_GUARDED_BY(rtcp_receiver_lock_); + uint32_t remote_sender_octet_count_ RTC_GUARDED_BY(rtcp_receiver_lock_); + // When did we receive the last send report. + NtpTime last_received_sr_ntp_ RTC_GUARDED_BY(rtcp_receiver_lock_); + + // Received XR receive time report. + rtcp::ReceiveTimeInfo remote_time_info_; + // Time when the report was received. + NtpTime last_received_xr_ntp_; + // Estimated rtt, zero when there is no valid estimate. + bool xr_rrtr_status_ RTC_GUARDED_BY(rtcp_receiver_lock_); + int64_t xr_rr_rtt_ms_; + + int64_t oldest_tmmbr_info_ms_ RTC_GUARDED_BY(rtcp_receiver_lock_); + // Mapped by remote ssrc. + std::map<uint32_t, TmmbrInformation> tmmbr_infos_ + RTC_GUARDED_BY(rtcp_receiver_lock_); + + ReportBlockMap received_report_blocks_ RTC_GUARDED_BY(rtcp_receiver_lock_); + std::map<uint32_t, LastFirStatus> last_fir_ + RTC_GUARDED_BY(rtcp_receiver_lock_); + std::map<uint32_t, std::string> received_cnames_ + RTC_GUARDED_BY(rtcp_receiver_lock_); + + // The last time we received an RTCP Report block for this module. + int64_t last_received_rb_ms_ RTC_GUARDED_BY(rtcp_receiver_lock_); + + // The time we last received an RTCP RR telling we have successfully + // delivered RTP packet to the remote side. + int64_t last_increased_sequence_number_ms_; + + RtcpStatisticsCallback* stats_callback_ RTC_GUARDED_BY(feedbacks_lock_); + + RtcpPacketTypeCounterObserver* const packet_type_counter_observer_; + RtcpPacketTypeCounter packet_type_counter_; + + RtcpNackStats nack_stats_; + + size_t num_skipped_packets_; + int64_t last_skipped_packets_warning_ms_; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc new file mode 100644 index 0000000000..0c3b8e241a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -0,0 +1,1280 @@ +/* + * 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 <memory> + +#include "api/array_view.h" +#include "common_types.h" // NOLINT(build/include) +#include "common_video/include/video_bitrate_allocator.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/app.h" +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" +#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" +#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtcp_packet/pli.h" +#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h" +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/remb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "modules/rtp_rtcp/source/rtcp_receiver.h" +#include "modules/rtp_rtcp/source/time_util.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/random.h" +#include "system_wrappers/include/ntp_time.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::_; +using ::testing::AllOf; +using ::testing::ElementsAreArray; +using ::testing::Field; +using ::testing::IsEmpty; +using ::testing::NiceMock; +using ::testing::Property; +using ::testing::SizeIs; +using ::testing::StrEq; +using ::testing::StrictMock; +using ::testing::UnorderedElementsAre; +using rtcp::ReceiveTimeInfo; + +class MockRtcpPacketTypeCounterObserver : public RtcpPacketTypeCounterObserver { + public: + MOCK_METHOD2(RtcpPacketTypesCounterUpdated, + void(uint32_t, const RtcpPacketTypeCounter&)); +}; + +class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver { + public: + MOCK_METHOD1(OnReceivedIntraFrameRequest, void(uint32_t)); +}; + +class MockRtcpCallbackImpl : public RtcpStatisticsCallback { + public: + MOCK_METHOD2(StatisticsUpdated, void(const RtcpStatistics&, uint32_t)); + MOCK_METHOD2(CNameChanged, void(const char*, uint32_t)); +}; + +class MockTransportFeedbackObserver : public TransportFeedbackObserver { + public: + MOCK_METHOD3(AddPacket, void(uint32_t, uint16_t, size_t)); + MOCK_METHOD4(AddPacket, + void(uint32_t, uint16_t, size_t, const PacedPacketInfo&)); + MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&)); + MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>()); +}; + +class MockRtcpBandwidthObserver : public RtcpBandwidthObserver { + public: + MOCK_METHOD1(OnReceivedEstimatedBitrate, void(uint32_t)); + MOCK_METHOD3(OnReceivedRtcpReceiverReport, + void(const ReportBlockList&, int64_t, int64_t)); +}; + +class MockModuleRtpRtcp : public RTCPReceiver::ModuleRtpRtcp { + public: + MOCK_METHOD4(GetSendReportMetadata, bool(uint32_t, uint64_t*, uint32_t*, uint64_t*)); + MOCK_METHOD1(SetTmmbn, void(std::vector<rtcp::TmmbItem>)); + MOCK_METHOD0(OnRequestSendReport, void()); + MOCK_METHOD1(OnReceivedNack, void(const std::vector<uint16_t>&)); + MOCK_METHOD1(OnReceivedRtcpReportBlocks, void(const ReportBlockList&)); +}; + +class MockVideoBitrateAllocationObserver + : public VideoBitrateAllocationObserver { + public: + MOCK_METHOD1(OnBitrateAllocationUpdated, + void(const BitrateAllocation& allocation)); +}; + +// SSRC of remote peer, that sends rtcp packet to the rtcp receiver under test. +constexpr uint32_t kSenderSsrc = 0x10203; +// SSRCs of local peer, that rtcp packet addressed to. +constexpr uint32_t kReceiverMainSsrc = 0x123456; +// RtcpReceiver can accept several ssrc, e.g. regular and rtx streams. +constexpr uint32_t kReceiverExtraSsrc = 0x1234567; +// SSRCs to ignore (i.e. not configured in RtcpReceiver). +constexpr uint32_t kNotToUsSsrc = 0x654321; +constexpr uint32_t kUnknownSenderSsrc = 0x54321; + +} // namespace + +class RtcpReceiverTest : public ::testing::Test { + protected: + RtcpReceiverTest() + : system_clock_(1335900000), + rtcp_receiver_(&system_clock_, + false, + &packet_type_counter_observer_, + &bandwidth_observer_, + &intra_frame_observer_, + &transport_feedback_observer_, + &bitrate_allocation_observer_, + &rtp_rtcp_impl_) {} + void SetUp() { + std::set<uint32_t> ssrcs = {kReceiverMainSsrc, kReceiverExtraSsrc}; + rtcp_receiver_.SetSsrcs(kReceiverMainSsrc, ssrcs); + + rtcp_receiver_.SetRemoteSSRC(kSenderSsrc); + } + + void InjectRtcpPacket(rtc::ArrayView<const uint8_t> raw) { + rtcp_receiver_.IncomingPacket(raw.data(), raw.size()); + } + + void InjectRtcpPacket(const rtcp::RtcpPacket& packet) { + rtc::Buffer raw = packet.Build(); + rtcp_receiver_.IncomingPacket(raw.data(), raw.size()); + } + + SimulatedClock system_clock_; + // Callbacks to packet_type_counter_observer are frequent but most of the time + // are not interesting. + NiceMock<MockRtcpPacketTypeCounterObserver> packet_type_counter_observer_; + StrictMock<MockRtcpBandwidthObserver> bandwidth_observer_; + StrictMock<MockRtcpIntraFrameObserver> intra_frame_observer_; + StrictMock<MockTransportFeedbackObserver> transport_feedback_observer_; + StrictMock<MockVideoBitrateAllocationObserver> bitrate_allocation_observer_; + StrictMock<MockModuleRtpRtcp> rtp_rtcp_impl_; + + RTCPReceiver rtcp_receiver_; +}; + +TEST_F(RtcpReceiverTest, BrokenPacketIsIgnored) { + const uint8_t bad_packet[] = {0, 0, 0, 0}; + EXPECT_CALL(packet_type_counter_observer_, + RtcpPacketTypesCounterUpdated(_, _)) + .Times(0); + InjectRtcpPacket(bad_packet); +} + +TEST_F(RtcpReceiverTest, InvalidFeedbackPacketIsIgnored) { + // Too short feedback packet. + const uint8_t bad_packet[] = {0x81, rtcp::Rtpfb::kPacketType, 0, 0}; + + // TODO(danilchap): Add expectation RtcpPacketTypesCounterUpdated + // is not called once parser would be adjusted to avoid that callback on + // semi-valid packets. + InjectRtcpPacket(bad_packet); +} + +TEST_F(RtcpReceiverTest, InjectSrPacket) { + EXPECT_FALSE(rtcp_receiver_.NTP(nullptr, nullptr, nullptr, nullptr, nullptr)); + + int64_t now = system_clock_.TimeInMilliseconds(); + rtcp::SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(IsEmpty())); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(IsEmpty(), _, now)); + InjectRtcpPacket(sr); + + EXPECT_TRUE(rtcp_receiver_.NTP(nullptr, nullptr, nullptr, nullptr, nullptr)); +} + +TEST_F(RtcpReceiverTest, InjectSrPacketFromUnknownSender) { + int64_t now = system_clock_.TimeInMilliseconds(); + rtcp::SenderReport sr; + sr.SetSenderSsrc(kUnknownSenderSsrc); + + // The parser will handle report blocks in Sender Report from other than his + // expected peer. + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, now)); + InjectRtcpPacket(sr); + + // But will not flag that he's gotten sender information. + EXPECT_FALSE(rtcp_receiver_.NTP(nullptr, nullptr, nullptr, nullptr, nullptr)); +} + +TEST_F(RtcpReceiverTest, InjectSrPacketCalculatesRTT) { + Random r(0x0123456789abcdef); + const int64_t kRttMs = r.Rand(1, 9 * 3600 * 1000); + const uint32_t kDelayNtp = r.Rand(0, 0x7fffffff); + const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + + int64_t rtt_ms = 0; + EXPECT_EQ( + -1, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr)); + + uint32_t sent_ntp = CompactNtp(system_clock_.CurrentNtpTime()); + system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + + rtcp::SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + rtcp::ReportBlock block; + block.SetMediaSsrc(kReceiverMainSsrc); + block.SetLastSr(sent_ntp); + block.SetDelayLastSr(kDelayNtp); + sr.AddReportBlock(block); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(sr); + + EXPECT_EQ( + 0, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr)); + EXPECT_NEAR(kRttMs, rtt_ms, 1); +} + +TEST_F(RtcpReceiverTest, InjectSrPacketCalculatesNegativeRTTAsOne) { + Random r(0x0123456789abcdef); + const int64_t kRttMs = r.Rand(-3600 * 1000, -1); + const uint32_t kDelayNtp = r.Rand(0, 0x7fffffff); + const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + + int64_t rtt_ms = 0; + EXPECT_EQ( + -1, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr)); + + uint32_t sent_ntp = CompactNtp(system_clock_.CurrentNtpTime()); + system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + + rtcp::SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + rtcp::ReportBlock block; + block.SetMediaSsrc(kReceiverMainSsrc); + block.SetLastSr(sent_ntp); + block.SetDelayLastSr(kDelayNtp); + sr.AddReportBlock(block); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1))); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(SizeIs(1), _, _)); + InjectRtcpPacket(sr); + + EXPECT_EQ( + 0, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr)); + EXPECT_EQ(1, rtt_ms); +} + +TEST_F(RtcpReceiverTest, InjectRrPacket) { + int64_t now = system_clock_.TimeInMilliseconds(); + rtcp::ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(IsEmpty())); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(IsEmpty(), _, now)); + InjectRtcpPacket(rr); + + std::vector<RTCPReportBlock> report_blocks; + rtcp_receiver_.StatisticsReceived(&report_blocks); + EXPECT_TRUE(report_blocks.empty()); +} + +TEST_F(RtcpReceiverTest, InjectRrPacketWithReportBlockNotToUsIgnored) { + int64_t now = system_clock_.TimeInMilliseconds(); + rtcp::ReportBlock rb; + rb.SetMediaSsrc(kNotToUsSsrc); + rtcp::ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + rr.AddReportBlock(rb); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(IsEmpty())); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(IsEmpty(), _, now)); + InjectRtcpPacket(rr); + + EXPECT_EQ(0, rtcp_receiver_.LastReceivedReportBlockMs()); + std::vector<RTCPReportBlock> received_blocks; + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_TRUE(received_blocks.empty()); +} + +TEST_F(RtcpReceiverTest, InjectRrPacketWithOneReportBlock) { + int64_t now = system_clock_.TimeInMilliseconds(); + + rtcp::ReportBlock rb; + rb.SetMediaSsrc(kReceiverMainSsrc); + rtcp::ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + rr.AddReportBlock(rb); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1))); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(SizeIs(1), _, now)); + InjectRtcpPacket(rr); + + EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs()); + std::vector<RTCPReportBlock> received_blocks; + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_EQ(1u, received_blocks.size()); +} + +TEST_F(RtcpReceiverTest, InjectSrPacketWithOneReportBlock) { + int64_t now = system_clock_.TimeInMilliseconds(); + + rtcp::ReportBlock rb; + rb.SetMediaSsrc(kReceiverMainSsrc); + rtcp::SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + sr.AddReportBlock(rb); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1))); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(SizeIs(1), _, now)); + InjectRtcpPacket(sr); + + EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs()); + std::vector<RTCPReportBlock> received_blocks; + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_EQ(1u, received_blocks.size()); +} + +TEST_F(RtcpReceiverTest, InjectRrPacketWithTwoReportBlocks) { + const uint16_t kSequenceNumbers[] = {10, 12423}; + const uint32_t kCumLost[] = {13, 555}; + const uint8_t kFracLost[] = {20, 11}; + int64_t now = system_clock_.TimeInMilliseconds(); + + rtcp::ReportBlock rb1; + rb1.SetMediaSsrc(kReceiverMainSsrc); + rb1.SetExtHighestSeqNum(kSequenceNumbers[0]); + rb1.SetFractionLost(10); + + rtcp::ReportBlock rb2; + rb2.SetMediaSsrc(kReceiverExtraSsrc); + rb2.SetExtHighestSeqNum(kSequenceNumbers[1]); + rb2.SetFractionLost(0); + + rtcp::ReceiverReport rr1; + rr1.SetSenderSsrc(kSenderSsrc); + rr1.AddReportBlock(rb1); + rr1.AddReportBlock(rb2); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(2))); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(SizeIs(2), _, now)); + InjectRtcpPacket(rr1); + + EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs()); + std::vector<RTCPReportBlock> received_blocks; + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_THAT(received_blocks, + UnorderedElementsAre(Field(&RTCPReportBlock::fraction_lost, 0), + Field(&RTCPReportBlock::fraction_lost, 10))); + + // Insert next receiver report with same ssrc but new values. + rtcp::ReportBlock rb3; + rb3.SetMediaSsrc(kReceiverMainSsrc); + rb3.SetExtHighestSeqNum(kSequenceNumbers[0]); + rb3.SetFractionLost(kFracLost[0]); + rb3.SetCumulativeLost(kCumLost[0]); + + rtcp::ReportBlock rb4; + rb4.SetMediaSsrc(kReceiverExtraSsrc); + rb4.SetExtHighestSeqNum(kSequenceNumbers[1]); + rb4.SetFractionLost(kFracLost[1]); + rb4.SetCumulativeLost(kCumLost[1]); + + rtcp::ReceiverReport rr2; + rr2.SetSenderSsrc(kSenderSsrc); + rr2.AddReportBlock(rb3); + rr2.AddReportBlock(rb4); + + // Advance time to make 1st sent time and 2nd sent time different. + system_clock_.AdvanceTimeMilliseconds(500); + now = system_clock_.TimeInMilliseconds(); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(2))); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(SizeIs(2), _, now)); + InjectRtcpPacket(rr2); + + received_blocks.clear(); + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_EQ(2u, received_blocks.size()); + EXPECT_THAT( + received_blocks, + UnorderedElementsAre( + AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc), + Field(&RTCPReportBlock::fraction_lost, kFracLost[0]), + Field(&RTCPReportBlock::packets_lost, kCumLost[0]), + Field(&RTCPReportBlock::extended_highest_sequence_number, + kSequenceNumbers[0])), + AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverExtraSsrc), + Field(&RTCPReportBlock::fraction_lost, kFracLost[1]), + Field(&RTCPReportBlock::packets_lost, kCumLost[1]), + Field(&RTCPReportBlock::extended_highest_sequence_number, + kSequenceNumbers[1])))); +} + +TEST_F(RtcpReceiverTest, InjectRrPacketsFromTwoRemoteSsrcs) { + const uint32_t kSenderSsrc2 = 0x20304; + const uint16_t kSequenceNumbers[] = {10, 12423}; + const uint32_t kCumLost[] = {13, 555}; + const uint8_t kFracLost[] = {20, 11}; + + rtcp::ReportBlock rb1; + rb1.SetMediaSsrc(kReceiverMainSsrc); + rb1.SetExtHighestSeqNum(kSequenceNumbers[0]); + rb1.SetFractionLost(kFracLost[0]); + rb1.SetCumulativeLost(kCumLost[0]); + rtcp::ReceiverReport rr1; + rr1.SetSenderSsrc(kSenderSsrc); + rr1.AddReportBlock(rb1); + + int64_t now = system_clock_.TimeInMilliseconds(); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1))); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(SizeIs(1), _, now)); + InjectRtcpPacket(rr1); + + EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs()); + + std::vector<RTCPReportBlock> received_blocks; + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_EQ(1u, received_blocks.size()); + EXPECT_EQ(kSenderSsrc, received_blocks[0].sender_ssrc); + EXPECT_EQ(kReceiverMainSsrc, received_blocks[0].source_ssrc); + EXPECT_EQ(kFracLost[0], received_blocks[0].fraction_lost); + EXPECT_EQ(kCumLost[0], received_blocks[0].packets_lost); + EXPECT_EQ(kSequenceNumbers[0], + received_blocks[0].extended_highest_sequence_number); + + rtcp::ReportBlock rb2; + rb2.SetMediaSsrc(kReceiverMainSsrc); + rb2.SetExtHighestSeqNum(kSequenceNumbers[1]); + rb2.SetFractionLost(kFracLost[1]); + rb2.SetCumulativeLost(kCumLost[1]); + rtcp::ReceiverReport rr2; + rr2.SetSenderSsrc(kSenderSsrc2); + rr2.AddReportBlock(rb2); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1))); + EXPECT_CALL(bandwidth_observer_, + OnReceivedRtcpReceiverReport(SizeIs(1), _, now)); + InjectRtcpPacket(rr2); + + received_blocks.clear(); + rtcp_receiver_.StatisticsReceived(&received_blocks); + ASSERT_EQ(2u, received_blocks.size()); + EXPECT_THAT( + received_blocks, + UnorderedElementsAre( + AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc), + Field(&RTCPReportBlock::sender_ssrc, kSenderSsrc), + Field(&RTCPReportBlock::fraction_lost, kFracLost[0]), + Field(&RTCPReportBlock::packets_lost, kCumLost[0]), + Field(&RTCPReportBlock::extended_highest_sequence_number, + kSequenceNumbers[0])), + AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc), + Field(&RTCPReportBlock::sender_ssrc, kSenderSsrc2), + Field(&RTCPReportBlock::fraction_lost, kFracLost[1]), + Field(&RTCPReportBlock::packets_lost, kCumLost[1]), + Field(&RTCPReportBlock::extended_highest_sequence_number, + kSequenceNumbers[1])))); +} + +TEST_F(RtcpReceiverTest, GetRtt) { + const uint32_t kSentCompactNtp = 0x1234; + const uint32_t kDelayCompactNtp = 0x222; + // No report block received. + EXPECT_EQ( + -1, rtcp_receiver_.RTT(kSenderSsrc, nullptr, nullptr, nullptr, nullptr)); + + rtcp::ReportBlock rb; + rb.SetMediaSsrc(kReceiverMainSsrc); + rb.SetLastSr(kSentCompactNtp); + rb.SetDelayLastSr(kDelayCompactNtp); + + rtcp::ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + rr.AddReportBlock(rb); + int64_t now = system_clock_.TimeInMilliseconds(); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr); + + EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs()); + EXPECT_EQ( + 0, rtcp_receiver_.RTT(kSenderSsrc, nullptr, nullptr, nullptr, nullptr)); +} + +// Ij packets are ignored. +TEST_F(RtcpReceiverTest, InjectIjWithNoItem) { + rtcp::ExtendedJitterReport ij; + InjectRtcpPacket(ij); +} + +// App packets are ignored. +TEST_F(RtcpReceiverTest, InjectApp) { + rtcp::App app; + app.SetSubType(30); + app.SetName(0x17a177e); + const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'}; + app.SetData(kData, sizeof(kData)); + + InjectRtcpPacket(app); +} + +TEST_F(RtcpReceiverTest, InjectSdesWithOneChunk) { + const char kCname[] = "alice@host"; + MockRtcpCallbackImpl callback; + rtcp_receiver_.RegisterRtcpStatisticsCallback(&callback); + rtcp::Sdes sdes; + sdes.AddCName(kSenderSsrc, kCname); + + EXPECT_CALL(callback, CNameChanged(StrEq(kCname), kSenderSsrc)); + InjectRtcpPacket(sdes); + + char cName[RTCP_CNAME_SIZE]; + EXPECT_EQ(0, rtcp_receiver_.CNAME(kSenderSsrc, cName)); + EXPECT_EQ(0, strncmp(cName, kCname, RTCP_CNAME_SIZE)); +} + +TEST_F(RtcpReceiverTest, InjectByePacket_RemovesCname) { + const char kCname[] = "alice@host"; + rtcp::Sdes sdes; + sdes.AddCName(kSenderSsrc, kCname); + + InjectRtcpPacket(sdes); + + char cName[RTCP_CNAME_SIZE]; + EXPECT_EQ(0, rtcp_receiver_.CNAME(kSenderSsrc, cName)); + + // Verify that BYE removes the CNAME. + rtcp::Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + + InjectRtcpPacket(bye); + + EXPECT_EQ(-1, rtcp_receiver_.CNAME(kSenderSsrc, cName)); +} + +TEST_F(RtcpReceiverTest, InjectByePacket_RemovesReportBlocks) { + rtcp::ReportBlock rb1; + rb1.SetMediaSsrc(kReceiverMainSsrc); + rtcp::ReportBlock rb2; + rb2.SetMediaSsrc(kReceiverExtraSsrc); + rtcp::ReceiverReport rr; + rr.SetSenderSsrc(kSenderSsrc); + rr.AddReportBlock(rb1); + rr.AddReportBlock(rb2); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr); + + std::vector<RTCPReportBlock> received_blocks; + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_EQ(2u, received_blocks.size()); + + // Verify that BYE removes the report blocks. + rtcp::Bye bye; + bye.SetSenderSsrc(kSenderSsrc); + + InjectRtcpPacket(bye); + + received_blocks.clear(); + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_TRUE(received_blocks.empty()); + + // Inject packet again. + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr); + + received_blocks.clear(); + rtcp_receiver_.StatisticsReceived(&received_blocks); + EXPECT_EQ(2u, received_blocks.size()); +} + +TEST_F(RtcpReceiverTest, InjectPliPacket) { + rtcp::Pli pli; + pli.SetMediaSsrc(kReceiverMainSsrc); + + EXPECT_CALL( + packet_type_counter_observer_, + RtcpPacketTypesCounterUpdated( + kReceiverMainSsrc, Field(&RtcpPacketTypeCounter::pli_packets, 1))); + EXPECT_CALL(intra_frame_observer_, + OnReceivedIntraFrameRequest(kReceiverMainSsrc)); + InjectRtcpPacket(pli); +} + +TEST_F(RtcpReceiverTest, PliPacketNotToUsIgnored) { + rtcp::Pli pli; + pli.SetMediaSsrc(kNotToUsSsrc); + + EXPECT_CALL( + packet_type_counter_observer_, + RtcpPacketTypesCounterUpdated( + kReceiverMainSsrc, Field(&RtcpPacketTypeCounter::pli_packets, 0))); + EXPECT_CALL(intra_frame_observer_, OnReceivedIntraFrameRequest(_)).Times(0); + InjectRtcpPacket(pli); +} + +TEST_F(RtcpReceiverTest, InjectFirPacket) { + rtcp::Fir fir; + fir.AddRequestTo(kReceiverMainSsrc, 13); + + EXPECT_CALL( + packet_type_counter_observer_, + RtcpPacketTypesCounterUpdated( + kReceiverMainSsrc, Field(&RtcpPacketTypeCounter::fir_packets, 1))); + EXPECT_CALL(intra_frame_observer_, + OnReceivedIntraFrameRequest(kReceiverMainSsrc)); + InjectRtcpPacket(fir); +} + +TEST_F(RtcpReceiverTest, FirPacketNotToUsIgnored) { + rtcp::Fir fir; + fir.AddRequestTo(kNotToUsSsrc, 13); + + EXPECT_CALL(intra_frame_observer_, OnReceivedIntraFrameRequest(_)).Times(0); + InjectRtcpPacket(fir); +} + +TEST_F(RtcpReceiverTest, ExtendedReportsPacketWithZeroReportBlocksIgnored) { + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + + InjectRtcpPacket(xr); +} + +// VOiP reports are ignored. +TEST_F(RtcpReceiverTest, InjectExtendedReportsVoipPacket) { + const uint8_t kLossRate = 123; + rtcp::VoipMetric voip_metric; + voip_metric.SetMediaSsrc(kReceiverMainSsrc); + RTCPVoIPMetric metric; + metric.lossRate = kLossRate; + voip_metric.SetVoipMetric(metric); + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetVoipMetric(voip_metric); + + InjectRtcpPacket(xr); +} + +TEST_F(RtcpReceiverTest, ExtendedReportsVoipPacketNotToUsIgnored) { + rtcp::VoipMetric voip_metric; + voip_metric.SetMediaSsrc(kNotToUsSsrc); + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetVoipMetric(voip_metric); + + InjectRtcpPacket(xr); +} + +TEST_F(RtcpReceiverTest, InjectExtendedReportsReceiverReferenceTimePacket) { + const NtpTime kNtp(0x10203, 0x40506); + rtcp::Rrtr rrtr; + rrtr.SetNtp(kNtp); + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetRrtr(rrtr); + + ReceiveTimeInfo rrtime; + EXPECT_FALSE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime)); + + InjectRtcpPacket(xr); + + EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime)); + EXPECT_EQ(rrtime.ssrc, kSenderSsrc); + EXPECT_EQ(rrtime.last_rr, CompactNtp(kNtp)); + EXPECT_EQ(0U, rrtime.delay_since_last_rr); + + system_clock_.AdvanceTimeMilliseconds(1500); + EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime)); + EXPECT_NEAR(1500, CompactNtpRttToMs(rrtime.delay_since_last_rr), 1); +} + +TEST_F(RtcpReceiverTest, ExtendedReportsDlrrPacketNotToUsIgnored) { + // Allow calculate rtt using dlrr/rrtr, simulating media receiver side. + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(ReceiveTimeInfo(kNotToUsSsrc, 0x12345, 0x67890)); + + InjectRtcpPacket(xr); + + int64_t rtt_ms = 0; + EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); +} + +TEST_F(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithSubBlock) { + const uint32_t kLastRR = 0x12345; + const uint32_t kDelay = 0x23456; + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + int64_t rtt_ms = 0; + EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); + + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, kLastRR, kDelay)); + + InjectRtcpPacket(xr); + + uint32_t compact_ntp_now = CompactNtp(system_clock_.CurrentNtpTime()); + EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); + uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR; + EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1); +} + +TEST_F(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithMultipleSubBlocks) { + const uint32_t kLastRR = 0x12345; + const uint32_t kDelay = 0x56789; + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, kLastRR, kDelay)); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc + 1, 0x12345, 0x67890)); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc + 2, 0x12345, 0x67890)); + + InjectRtcpPacket(xr); + + uint32_t compact_ntp_now = CompactNtp(system_clock_.CurrentNtpTime()); + int64_t rtt_ms = 0; + EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); + uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR; + EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1); +} + +TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithMultipleReportBlocks) { + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + + rtcp::Rrtr rrtr; + rtcp::VoipMetric metric; + metric.SetMediaSsrc(kReceiverMainSsrc); + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetRrtr(rrtr); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0x12345, 0x67890)); + xr.SetVoipMetric(metric); + + InjectRtcpPacket(xr); + + ReceiveTimeInfo rrtime; + EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime)); + int64_t rtt_ms = 0; + EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); +} + +TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithUnknownReportBlock) { + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + + rtcp::Rrtr rrtr; + rtcp::VoipMetric metric; + metric.SetMediaSsrc(kReceiverMainSsrc); + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetRrtr(rrtr); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0x12345, 0x67890)); + xr.SetVoipMetric(metric); + + rtc::Buffer packet = xr.Build(); + // Modify the DLRR block to have an unsupported block type, from 5 to 6. + ASSERT_EQ(5, packet.data()[20]); + packet.data()[20] = 6; + InjectRtcpPacket(packet); + + // Validate Rrtr was received and processed. + ReceiveTimeInfo rrtime; + EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime)); + // Validate Dlrr report wasn't processed. + int64_t rtt_ms = 0; + EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); +} + +TEST_F(RtcpReceiverTest, TestExtendedReportsRrRttInitiallyFalse) { + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + + int64_t rtt_ms; + EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); +} + +TEST_F(RtcpReceiverTest, RttCalculatedAfterExtendedReportsDlrr) { + Random rand(0x0123456789abcdef); + const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); + const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + NtpTime now = system_clock_.CurrentNtpTime(); + uint32_t sent_ntp = CompactNtp(now); + system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, sent_ntp, kDelayNtp)); + + InjectRtcpPacket(xr); + + int64_t rtt_ms = 0; + EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); + EXPECT_NEAR(kRttMs, rtt_ms, 1); +} + +TEST_F(RtcpReceiverTest, XrDlrrCalculatesNegativeRttAsOne) { + Random rand(0x0123456789abcdef); + const int64_t kRttMs = rand.Rand(-3600 * 1000, -1); + const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); + const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + NtpTime now = system_clock_.CurrentNtpTime(); + uint32_t sent_ntp = CompactNtp(now); + system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + rtcp_receiver_.SetRtcpXrRrtrStatus(true); + + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, sent_ntp, kDelayNtp)); + + InjectRtcpPacket(xr); + + int64_t rtt_ms = 0; + EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)); + EXPECT_EQ(1, rtt_ms); +} + +TEST_F(RtcpReceiverTest, LastReceivedXrReferenceTimeInfoInitiallyFalse) { + ReceiveTimeInfo info; + EXPECT_FALSE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info)); +} + +TEST_F(RtcpReceiverTest, GetLastReceivedExtendedReportsReferenceTimeInfo) { + const NtpTime kNtp(0x10203, 0x40506); + const uint32_t kNtpMid = CompactNtp(kNtp); + + rtcp::Rrtr rrtr; + rrtr.SetNtp(kNtp); + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.SetRrtr(rrtr); + + InjectRtcpPacket(xr); + + ReceiveTimeInfo info; + EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info)); + EXPECT_EQ(kSenderSsrc, info.ssrc); + EXPECT_EQ(kNtpMid, info.last_rr); + EXPECT_EQ(0U, info.delay_since_last_rr); + + system_clock_.AdvanceTimeMilliseconds(1000); + EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info)); + EXPECT_EQ(65536U, info.delay_since_last_rr); +} + +TEST_F(RtcpReceiverTest, ReceiveReportTimeout) { + const int64_t kRtcpIntervalMs = 1000; + const uint16_t kSequenceNumber = 1234; + system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs); + + // No RR received, shouldn't trigger a timeout. + EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); + EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); + + // Add a RR and advance the clock just enough to not trigger a timeout. + rtcp::ReportBlock rb1; + rb1.SetMediaSsrc(kReceiverMainSsrc); + rb1.SetExtHighestSeqNum(kSequenceNumber); + rtcp::ReceiverReport rr1; + rr1.SetSenderSsrc(kSenderSsrc); + rr1.AddReportBlock(rb1); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr1); + + system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs - 1); + EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); + EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); + + // Add a RR with the same extended max as the previous RR to trigger a + // sequence number timeout, but not a RR timeout. + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr1); + + system_clock_.AdvanceTimeMilliseconds(2); + EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); + EXPECT_TRUE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); + + // Advance clock enough to trigger an RR timeout too. + system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs); + EXPECT_TRUE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); + + // We should only get one timeout even though we still haven't received a new + // RR. + EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); + EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); + + // Add a new RR with increase sequence number to reset timers. + rtcp::ReportBlock rb2; + rb2.SetMediaSsrc(kReceiverMainSsrc); + rb2.SetExtHighestSeqNum(kSequenceNumber + 1); + rtcp::ReceiverReport rr2; + rr2.SetSenderSsrc(kSenderSsrc); + rr2.AddReportBlock(rb2); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr2); + + EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); + EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); + + // Verify we can get a timeout again once we've received new RR. + system_clock_.AdvanceTimeMilliseconds(2 * kRtcpIntervalMs); + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr2); + + system_clock_.AdvanceTimeMilliseconds(kRtcpIntervalMs + 1); + EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); + EXPECT_TRUE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); + + system_clock_.AdvanceTimeMilliseconds(2 * kRtcpIntervalMs); + EXPECT_TRUE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs)); +} + +TEST_F(RtcpReceiverTest, TmmbrReceivedWithNoIncomingPacket) { + EXPECT_EQ(0u, rtcp_receiver_.TmmbrReceived().size()); +} + +TEST_F(RtcpReceiverTest, TmmbrPacketAccepted) { + const uint32_t kBitrateBps = 30000; + rtcp::Tmmbr tmmbr; + tmmbr.SetSenderSsrc(kSenderSsrc); + tmmbr.AddTmmbr(rtcp::TmmbItem(kReceiverMainSsrc, kBitrateBps, 0)); + rtcp::SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + rtcp::CompoundPacket compound; + compound.Append(&sr); + compound.Append(&tmmbr); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(rtp_rtcp_impl_, SetTmmbn(SizeIs(1))); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(kBitrateBps)); + InjectRtcpPacket(compound); + + std::vector<rtcp::TmmbItem> tmmbr_received = rtcp_receiver_.TmmbrReceived(); + ASSERT_EQ(1u, tmmbr_received.size()); + EXPECT_EQ(kBitrateBps, tmmbr_received[0].bitrate_bps()); + EXPECT_EQ(kSenderSsrc, tmmbr_received[0].ssrc()); +} + +TEST_F(RtcpReceiverTest, TmmbrPacketNotForUsIgnored) { + const uint32_t kBitrateBps = 30000; + rtcp::Tmmbr tmmbr; + tmmbr.SetSenderSsrc(kSenderSsrc); + tmmbr.AddTmmbr(rtcp::TmmbItem(kNotToUsSsrc, kBitrateBps, 0)); + + rtcp::SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + rtcp::CompoundPacket compound; + compound.Append(&sr); + compound.Append(&tmmbr); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(_)).Times(0); + InjectRtcpPacket(compound); + + EXPECT_EQ(0u, rtcp_receiver_.TmmbrReceived().size()); +} + +TEST_F(RtcpReceiverTest, TmmbrPacketZeroRateIgnored) { + rtcp::Tmmbr tmmbr; + tmmbr.SetSenderSsrc(kSenderSsrc); + tmmbr.AddTmmbr(rtcp::TmmbItem(kReceiverMainSsrc, 0, 0)); + rtcp::SenderReport sr; + sr.SetSenderSsrc(kSenderSsrc); + rtcp::CompoundPacket compound; + compound.Append(&sr); + compound.Append(&tmmbr); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(_)).Times(0); + InjectRtcpPacket(compound); + + EXPECT_EQ(0u, rtcp_receiver_.TmmbrReceived().size()); +} + +TEST_F(RtcpReceiverTest, TmmbrThreeConstraintsTimeOut) { + // Inject 3 packets "from" kSenderSsrc, kSenderSsrc+1, kSenderSsrc+2. + // The times of arrival are starttime + 0, starttime + 5 and starttime + 10. + for (uint32_t ssrc = kSenderSsrc; ssrc < kSenderSsrc + 3; ++ssrc) { + rtcp::Tmmbr tmmbr; + tmmbr.SetSenderSsrc(ssrc); + tmmbr.AddTmmbr(rtcp::TmmbItem(kReceiverMainSsrc, 30000, 0)); + rtcp::SenderReport sr; + sr.SetSenderSsrc(ssrc); + rtcp::CompoundPacket compound; + compound.Append(&sr); + compound.Append(&tmmbr); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(rtp_rtcp_impl_, SetTmmbn(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(_)); + InjectRtcpPacket(compound); + + // 5 seconds between each packet. + system_clock_.AdvanceTimeMilliseconds(5000); + } + // It is now starttime + 15. + std::vector<rtcp::TmmbItem> candidate_set = rtcp_receiver_.TmmbrReceived(); + ASSERT_EQ(3u, candidate_set.size()); + EXPECT_EQ(30000U, candidate_set[0].bitrate_bps()); + + // We expect the timeout to be 25 seconds. Advance the clock by 12 + // seconds, timing out the first packet. + system_clock_.AdvanceTimeMilliseconds(12000); + candidate_set = rtcp_receiver_.TmmbrReceived(); + ASSERT_EQ(2u, candidate_set.size()); + EXPECT_EQ(kSenderSsrc + 1, candidate_set[0].ssrc()); +} + +TEST_F(RtcpReceiverTest, Callbacks) { + MockRtcpCallbackImpl callback; + rtcp_receiver_.RegisterRtcpStatisticsCallback(&callback); + + const uint8_t kFractionLoss = 3; + const uint32_t kCumulativeLoss = 7; + const uint32_t kJitter = 9; + const uint16_t kSequenceNumber = 1234; + + // First packet, all numbers should just propagate. + rtcp::ReportBlock rb1; + rb1.SetMediaSsrc(kReceiverMainSsrc); + rb1.SetExtHighestSeqNum(kSequenceNumber); + rb1.SetFractionLost(kFractionLoss); + rb1.SetCumulativeLost(kCumulativeLoss); + rb1.SetJitter(kJitter); + + rtcp::ReceiverReport rr1; + rr1.SetSenderSsrc(kSenderSsrc); + rr1.AddReportBlock(rb1); + EXPECT_CALL(callback, + StatisticsUpdated( + AllOf(Field(&RtcpStatistics::fraction_lost, kFractionLoss), + Field(&RtcpStatistics::packets_lost, kCumulativeLoss), + Field(&RtcpStatistics::extended_highest_sequence_number, + kSequenceNumber), + Field(&RtcpStatistics::jitter, kJitter)), + kReceiverMainSsrc)); + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + InjectRtcpPacket(rr1); + + rtcp_receiver_.RegisterRtcpStatisticsCallback(nullptr); + + // Add arbitrary numbers, callback should not be called. + rtcp::ReportBlock rb2; + rb2.SetMediaSsrc(kReceiverMainSsrc); + rb2.SetExtHighestSeqNum(kSequenceNumber + 1); + rb2.SetFractionLost(42); + rb2.SetCumulativeLost(137); + rb2.SetJitter(4711); + + rtcp::ReceiverReport rr2; + rr2.SetSenderSsrc(kSenderSsrc); + rr2.AddReportBlock(rb2); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_)); + EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _)); + EXPECT_CALL(callback, StatisticsUpdated(_, _)).Times(0); + InjectRtcpPacket(rr2); +} + +TEST_F(RtcpReceiverTest, ReceivesTransportFeedback) { + rtcp::TransportFeedback packet; + packet.SetMediaSsrc(kReceiverMainSsrc); + packet.SetSenderSsrc(kSenderSsrc); + packet.SetBase(1, 1000); + packet.AddReceivedPacket(1, 1000); + + EXPECT_CALL( + transport_feedback_observer_, + OnTransportFeedback(AllOf( + Property(&rtcp::TransportFeedback::media_ssrc, kReceiverMainSsrc), + Property(&rtcp::TransportFeedback::sender_ssrc, kSenderSsrc)))); + InjectRtcpPacket(packet); +} + +TEST_F(RtcpReceiverTest, ReceivesRemb) { + const uint32_t kBitrateBps = 500000; + rtcp::Remb remb; + remb.SetSenderSsrc(kSenderSsrc); + remb.SetBitrateBps(kBitrateBps); + + EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(kBitrateBps)); + InjectRtcpPacket(remb); +} + +TEST_F(RtcpReceiverTest, HandlesInvalidTransportFeedback) { + // Send a compound packet with a TransportFeedback followed by something else. + rtcp::TransportFeedback packet; + packet.SetMediaSsrc(kReceiverMainSsrc); + packet.SetSenderSsrc(kSenderSsrc); + packet.SetBase(1, 1000); + packet.AddReceivedPacket(1, 1000); + + static uint32_t kBitrateBps = 50000; + rtcp::Remb remb; + remb.SetSenderSsrc(kSenderSsrc); + remb.SetBitrateBps(kBitrateBps); + rtcp::CompoundPacket compound; + compound.Append(&packet); + compound.Append(&remb); + rtc::Buffer built_packet = compound.Build(); + + // Modify the TransportFeedback packet so that it is invalid. + const size_t kStatusCountOffset = 14; + ByteWriter<uint16_t>::WriteBigEndian( + &built_packet.data()[kStatusCountOffset], 42); + + // Stress no transport feedback is expected. + EXPECT_CALL(transport_feedback_observer_, OnTransportFeedback(_)).Times(0); + // But remb should be processed and cause a callback + EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(kBitrateBps)); + InjectRtcpPacket(built_packet); +} + +TEST_F(RtcpReceiverTest, Nack) { + const uint16_t kNackList1[] = {1, 2, 3, 5}; + const uint16_t kNackList23[] = {5, 7, 30, 40, 41, 58, 59, 61, 63}; + const size_t kNackListLength2 = 4; + const size_t kNackListLength3 = arraysize(kNackList23) - kNackListLength2; + std::set<uint16_t> nack_set; + nack_set.insert(std::begin(kNackList1), std::end(kNackList1)); + nack_set.insert(std::begin(kNackList23), std::end(kNackList23)); + + rtcp::Nack nack1; + nack1.SetSenderSsrc(kSenderSsrc); + nack1.SetMediaSsrc(kReceiverMainSsrc); + nack1.SetPacketIds(kNackList1, arraysize(kNackList1)); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedNack(ElementsAreArray(kNackList1))); + EXPECT_CALL(packet_type_counter_observer_, + RtcpPacketTypesCounterUpdated( + kReceiverMainSsrc, + AllOf(Field(&RtcpPacketTypeCounter::nack_requests, + arraysize(kNackList1)), + Field(&RtcpPacketTypeCounter::unique_nack_requests, + arraysize(kNackList1))))); + InjectRtcpPacket(nack1); + + rtcp::Nack nack2; + nack2.SetSenderSsrc(kSenderSsrc); + nack2.SetMediaSsrc(kReceiverMainSsrc); + nack2.SetPacketIds(kNackList23, kNackListLength2); + + rtcp::Nack nack3; + nack3.SetSenderSsrc(kSenderSsrc); + nack3.SetMediaSsrc(kReceiverMainSsrc); + nack3.SetPacketIds(kNackList23 + kNackListLength2, kNackListLength3); + + rtcp::CompoundPacket two_nacks; + two_nacks.Append(&nack2); + two_nacks.Append(&nack3); + + EXPECT_CALL(rtp_rtcp_impl_, OnReceivedNack(ElementsAreArray(kNackList23))); + EXPECT_CALL(packet_type_counter_observer_, + RtcpPacketTypesCounterUpdated( + kReceiverMainSsrc, + AllOf(Field(&RtcpPacketTypeCounter::nack_requests, + arraysize(kNackList1) + arraysize(kNackList23)), + Field(&RtcpPacketTypeCounter::unique_nack_requests, + nack_set.size())))); + InjectRtcpPacket(two_nacks); +} + +TEST_F(RtcpReceiverTest, NackNotForUsIgnored) { + const uint16_t kNackList1[] = {1, 2, 3, 5}; + const size_t kNackListLength1 = std::end(kNackList1) - std::begin(kNackList1); + + rtcp::Nack nack; + nack.SetSenderSsrc(kSenderSsrc); + nack.SetMediaSsrc(kNotToUsSsrc); + nack.SetPacketIds(kNackList1, kNackListLength1); + + EXPECT_CALL(packet_type_counter_observer_, + RtcpPacketTypesCounterUpdated( + _, Field(&RtcpPacketTypeCounter::nack_requests, 0))); + InjectRtcpPacket(nack); +} + +TEST_F(RtcpReceiverTest, ForceSenderReport) { + rtcp::RapidResyncRequest rr; + rr.SetSenderSsrc(kSenderSsrc); + rr.SetMediaSsrc(kReceiverMainSsrc); + + EXPECT_CALL(rtp_rtcp_impl_, OnRequestSendReport()); + InjectRtcpPacket(rr); +} + +TEST_F(RtcpReceiverTest, ReceivesTargetBitrate) { + BitrateAllocation expected_allocation; + expected_allocation.SetBitrate(0, 0, 10000); + expected_allocation.SetBitrate(0, 1, 20000); + expected_allocation.SetBitrate(1, 0, 40000); + expected_allocation.SetBitrate(1, 1, 80000); + + rtcp::TargetBitrate bitrate; + bitrate.AddTargetBitrate(0, 0, expected_allocation.GetBitrate(0, 0) / 1000); + bitrate.AddTargetBitrate(0, 1, expected_allocation.GetBitrate(0, 1) / 1000); + bitrate.AddTargetBitrate(1, 0, expected_allocation.GetBitrate(1, 0) / 1000); + bitrate.AddTargetBitrate(1, 1, expected_allocation.GetBitrate(1, 1) / 1000); + + rtcp::ExtendedReports xr; + xr.SetTargetBitrate(bitrate); + + // Wrong sender ssrc, target bitrate should be discarded. + xr.SetSenderSsrc(kSenderSsrc + 1); + EXPECT_CALL(bitrate_allocation_observer_, + OnBitrateAllocationUpdated(expected_allocation)) + .Times(0); + InjectRtcpPacket(xr); + + // Set correct ssrc, callback should be called once. + xr.SetSenderSsrc(kSenderSsrc); + EXPECT_CALL(bitrate_allocation_observer_, + OnBitrateAllocationUpdated(expected_allocation)); + InjectRtcpPacket(xr); +} + +TEST_F(RtcpReceiverTest, HandlesIncorrectTargetBitrate) { + BitrateAllocation expected_allocation; + expected_allocation.SetBitrate(0, 0, 10000); + + rtcp::TargetBitrate bitrate; + bitrate.AddTargetBitrate(0, 0, expected_allocation.GetBitrate(0, 0) / 1000); + bitrate.AddTargetBitrate(0, kMaxTemporalStreams, 20000); + bitrate.AddTargetBitrate(kMaxSpatialLayers, 0, 40000); + + rtcp::ExtendedReports xr; + xr.SetTargetBitrate(bitrate); + xr.SetSenderSsrc(kSenderSsrc); + + EXPECT_CALL(bitrate_allocation_observer_, + OnBitrateAllocationUpdated(expected_allocation)); + InjectRtcpPacket(xr); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc new file mode 100644 index 0000000000..fed18fca68 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc @@ -0,0 +1,1027 @@ +/* + * 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 "modules/rtp_rtcp/source/rtcp_sender.h" + +#include <string.h> // memcpy + +#include <utility> + +#include "common_types.h" // NOLINT(build/include) +#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h" +#include "logging/rtc_event_log/rtc_event_log.h" +#include "modules/rtp_rtcp/source/rtcp_packet/app.h" +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" +#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" +#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtcp_packet/pli.h" +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/remb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h" +#include "modules/rtp_rtcp/source/time_util.h" +#include "modules/rtp_rtcp/source/tmmbr_help.h" +#include "rtc_base/checks.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/logging.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/trace_event.h" + +namespace webrtc { + +namespace { +const uint32_t kRtcpAnyExtendedReports = + kRtcpXrVoipMetric | kRtcpXrReceiverReferenceTime | kRtcpXrDlrrReportBlock | + kRtcpXrTargetBitrate; +} // namespace + +NACKStringBuilder::NACKStringBuilder() + : stream_(""), count_(0), prevNack_(0), consecutive_(false) {} + +NACKStringBuilder::~NACKStringBuilder() {} + +void NACKStringBuilder::PushNACK(uint16_t nack) { + if (count_ == 0) { + stream_ << nack; + } else if (nack == prevNack_ + 1) { + consecutive_ = true; + } else { + if (consecutive_) { + stream_ << "-" << prevNack_; + consecutive_ = false; + } + stream_ << "," << nack; + } + count_++; + prevNack_ = nack; +} + +std::string NACKStringBuilder::GetResult() { + if (consecutive_) { + stream_ << "-" << prevNack_; + consecutive_ = false; + } + return stream_.str(); +} + +RTCPSender::FeedbackState::FeedbackState() + : packets_sent(0), + media_bytes_sent(0), + send_bitrate(0), + last_rr_ntp_secs(0), + last_rr_ntp_frac(0), + remote_sr(0), + has_last_xr_rr(false), + module(nullptr) {} + +class PacketContainer : public rtcp::CompoundPacket, + public rtcp::RtcpPacket::PacketReadyCallback { + public: + PacketContainer(Transport* transport, RtcEventLog* event_log) + : transport_(transport), event_log_(event_log), bytes_sent_(0) {} + virtual ~PacketContainer() { + for (RtcpPacket* packet : appended_packets_) + delete packet; + } + + void OnPacketReady(uint8_t* data, size_t length) override { + if (transport_->SendRtcp(data, length)) { + bytes_sent_ += length; + if (event_log_) { + event_log_->Log(rtc::MakeUnique<RtcEventRtcpPacketOutgoing>( + rtc::ArrayView<const uint8_t>(data, length))); + } + } + } + + size_t SendPackets(size_t max_payload_length) { + RTC_DCHECK_LE(max_payload_length, IP_PACKET_SIZE); + uint8_t buffer[IP_PACKET_SIZE]; + BuildExternalBuffer(buffer, max_payload_length, this); + return bytes_sent_; + } + + private: + Transport* transport_; + RtcEventLog* const event_log_; + size_t bytes_sent_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(PacketContainer); +}; + +class RTCPSender::RtcpContext { + public: + RtcpContext(const FeedbackState& feedback_state, + int32_t nack_size, + const uint16_t* nack_list, + NtpTime now) + : feedback_state_(feedback_state), + nack_size_(nack_size), + nack_list_(nack_list), + now_(now) {} + + const FeedbackState& feedback_state_; + const int32_t nack_size_; + const uint16_t* nack_list_; + const NtpTime now_; +}; + +RTCPSender::RTCPSender( + bool audio, + Clock* clock, + ReceiveStatisticsProvider* receive_statistics, + RtcpPacketTypeCounterObserver* packet_type_counter_observer, + RtcEventLog* event_log, + Transport* outgoing_transport) + : audio_(audio), + clock_(clock), + random_(clock_->TimeInMicroseconds()), + method_(RtcpMode::kOff), + event_log_(event_log), + transport_(outgoing_transport), + using_nack_(false), + sending_(false), + next_time_to_send_rtcp_(clock->TimeInMilliseconds()), + timestamp_offset_(0), + last_rtp_timestamp_(0), + last_frame_capture_time_ms_(-1), + ssrc_(0), + remote_ssrc_(0), + receive_statistics_(receive_statistics), + + sequence_number_fir_(0), + + remb_bitrate_(0), + + tmmbr_send_bps_(0), + packet_oh_send_(0), + max_packet_size_(IP_PACKET_SIZE - 28), // IPv4 + UDP by default. + + app_sub_type_(0), + app_name_(0), + app_data_(nullptr), + app_length_(0), + + xr_send_receiver_reference_time_enabled_(false), + packet_type_counter_observer_(packet_type_counter_observer) { + memset(last_send_report_, 0, sizeof(last_send_report_)); + memset(last_rtcp_time_, 0, sizeof(last_rtcp_time_)); + memset(lastSRPacketCount_, 0, sizeof(lastSRPacketCount_)); + memset(lastSROctetCount_, 0, sizeof(lastSROctetCount_)); + RTC_DCHECK(transport_ != nullptr); + + builders_[kRtcpSr] = &RTCPSender::BuildSR; + builders_[kRtcpRr] = &RTCPSender::BuildRR; + builders_[kRtcpSdes] = &RTCPSender::BuildSDES; + builders_[kRtcpPli] = &RTCPSender::BuildPLI; + builders_[kRtcpFir] = &RTCPSender::BuildFIR; + builders_[kRtcpRemb] = &RTCPSender::BuildREMB; + builders_[kRtcpBye] = &RTCPSender::BuildBYE; + builders_[kRtcpApp] = &RTCPSender::BuildAPP; + builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR; + builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN; + builders_[kRtcpNack] = &RTCPSender::BuildNACK; + builders_[kRtcpAnyExtendedReports] = &RTCPSender::BuildExtendedReports; +} + +RTCPSender::~RTCPSender() {} + +RtcpMode RTCPSender::Status() const { + rtc::CritScope lock(&critical_section_rtcp_sender_); + return method_; +} + +void RTCPSender::SetRTCPStatus(RtcpMode new_method) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + + if (method_ == RtcpMode::kOff && new_method != RtcpMode::kOff) { + // When switching on, reschedule the next packet + next_time_to_send_rtcp_ = + clock_->TimeInMilliseconds() + RTCP_INTERVAL_RAPID_SYNC_MS / 2; + } + method_ = new_method; +} + +bool RTCPSender::Sending() const { + rtc::CritScope lock(&critical_section_rtcp_sender_); + return sending_; +} + +int32_t RTCPSender::SetSendingStatus(const FeedbackState& feedback_state, + bool sending) { + bool sendRTCPBye = false; + { + rtc::CritScope lock(&critical_section_rtcp_sender_); + + if (method_ != RtcpMode::kOff) { + if (sending == false && sending_ == true) { + // Trigger RTCP bye + sendRTCPBye = true; + } + } + sending_ = sending; + } + if (sendRTCPBye) + return SendRTCP(feedback_state, kRtcpBye); + return 0; +} + +void RTCPSender::SetRemb(uint32_t bitrate, const std::vector<uint32_t>& ssrcs) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + remb_bitrate_ = bitrate; + remb_ssrcs_ = ssrcs; + + SetFlag(kRtcpRemb, /*is_volatile=*/false); + // Send a REMB immediately if we have a new REMB. The frequency of REMBs is + // throttled by the caller. + next_time_to_send_rtcp_ = clock_->TimeInMilliseconds(); +} + +void RTCPSender::UnsetRemb() { + rtc::CritScope lock(&critical_section_rtcp_sender_); + // Stop sending REMB each report until it is reenabled and REMB data set. + ConsumeFlag(kRtcpRemb, /*forced=*/true); +} + +bool RTCPSender::TMMBR() const { + rtc::CritScope lock(&critical_section_rtcp_sender_); + return IsFlagPresent(RTCPPacketType::kRtcpTmmbr); +} + +void RTCPSender::SetTMMBRStatus(bool enable) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + if (enable) { + SetFlag(RTCPPacketType::kRtcpTmmbr, false); + } else { + ConsumeFlag(RTCPPacketType::kRtcpTmmbr, true); + } +} + +void RTCPSender::SetMaxRtpPacketSize(size_t max_packet_size) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + max_packet_size_ = max_packet_size; +} + +void RTCPSender::SetTimestampOffset(uint32_t timestamp_offset) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + timestamp_offset_ = timestamp_offset; +} + +void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp, + int64_t capture_time_ms) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + last_rtp_timestamp_ = rtp_timestamp; + if (capture_time_ms < 0) { + // We don't currently get a capture time from VoiceEngine. + last_frame_capture_time_ms_ = clock_->TimeInMilliseconds(); + } else { + last_frame_capture_time_ms_ = capture_time_ms; + } +} + +uint32_t RTCPSender::SSRC() const { + rtc::CritScope lock(&critical_section_rtcp_sender_); + return ssrc_; +} + +void RTCPSender::SetSSRC(uint32_t ssrc) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + + if (ssrc_ != 0) { + // not first SetSSRC, probably due to a collision + // schedule a new RTCP report + // make sure that we send a RTP packet + next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + 100; + } + ssrc_ = ssrc; +} + +void RTCPSender::SetRemoteSSRC(uint32_t ssrc) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + remote_ssrc_ = ssrc; +} + +int32_t RTCPSender::SetCNAME(const char* c_name) { + if (!c_name) + return -1; + + RTC_DCHECK_LT(strlen(c_name), RTCP_CNAME_SIZE); + rtc::CritScope lock(&critical_section_rtcp_sender_); + cname_ = c_name; + return 0; +} + +int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC, const char* c_name) { + RTC_DCHECK(c_name); + RTC_DCHECK_LT(strlen(c_name), RTCP_CNAME_SIZE); + rtc::CritScope lock(&critical_section_rtcp_sender_); + // One spot is reserved for ssrc_/cname_. + // TODO(danilchap): Add support for more than 30 contributes by sending + // several sdes packets. + if (csrc_cnames_.size() >= rtcp::Sdes::kMaxNumberOfChunks - 1) + return -1; + + csrc_cnames_[SSRC] = c_name; + return 0; +} + +int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + auto it = csrc_cnames_.find(SSRC); + + if (it == csrc_cnames_.end()) + return -1; + + csrc_cnames_.erase(it); + return 0; +} + +bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const { + /* + For audio we use a fix 5 sec interval + + For video we use 1 sec interval fo a BW smaller than 360 kbit/s, + technicaly we break the max 5% RTCP BW for video below 10 kbit/s but + that should be extremely rare + + + From RFC 3550 + + MAX RTCP BW is 5% if the session BW + A send report is approximately 65 bytes inc CNAME + A receiver report is approximately 28 bytes + + The RECOMMENDED value for the reduced minimum in seconds is 360 + divided by the session bandwidth in kilobits/second. This minimum + is smaller than 5 seconds for bandwidths greater than 72 kb/s. + + If the participant has not yet sent an RTCP packet (the variable + initial is true), the constant Tmin is set to 2.5 seconds, else it + is set to 5 seconds. + + The interval between RTCP packets is varied randomly over the + range [0.5,1.5] times the calculated interval to avoid unintended + synchronization of all participants + + if we send + If the participant is a sender (we_sent true), the constant C is + set to the average RTCP packet size (avg_rtcp_size) divided by 25% + of the RTCP bandwidth (rtcp_bw), and the constant n is set to the + number of senders. + + if we receive only + If we_sent is not true, the constant C is set + to the average RTCP packet size divided by 75% of the RTCP + bandwidth. The constant n is set to the number of receivers + (members - senders). If the number of senders is greater than + 25%, senders and receivers are treated together. + + reconsideration NOT required for peer-to-peer + "timer reconsideration" is + employed. This algorithm implements a simple back-off mechanism + which causes users to hold back RTCP packet transmission if the + group sizes are increasing. + + n = number of members + C = avg_size/(rtcpBW/4) + + 3. The deterministic calculated interval Td is set to max(Tmin, n*C). + + 4. The calculated interval T is set to a number uniformly distributed + between 0.5 and 1.5 times the deterministic calculated interval. + + 5. The resulting value of T is divided by e-3/2=1.21828 to compensate + for the fact that the timer reconsideration algorithm converges to + a value of the RTCP bandwidth below the intended average + */ + + int64_t now = clock_->TimeInMilliseconds(); + + rtc::CritScope lock(&critical_section_rtcp_sender_); + + if (method_ == RtcpMode::kOff) + return false; + + if (!audio_ && sendKeyframeBeforeRTP) { + // for video key-frames we want to send the RTCP before the large key-frame + // if we have a 100 ms margin + now += RTCP_SEND_BEFORE_KEY_FRAME_MS; + } + + if (now >= next_time_to_send_rtcp_) { + return true; + } else if (now < 0x0000ffff && + next_time_to_send_rtcp_ > 0xffff0000) { // 65 sec margin + // wrap + return true; + } + return false; +} + +bool +RTCPSender::GetSendReportMetadata(const uint32_t sendReport, + uint64_t *timeOfSend, + uint32_t *packetCount, + uint64_t *octetCount) +{ + rtc::CritScope lock(&critical_section_rtcp_sender_); + + // This is only saved when we are the sender + if ((last_send_report_[0] == 0) || (sendReport == 0)) { + return false; + } else { + for (int i = 0; i < RTCP_NUMBER_OF_SR; ++i) { + if (last_send_report_[i] == sendReport) { + *timeOfSend = last_rtcp_time_[i]; + *packetCount = lastSRPacketCount_[i]; + *octetCount = lastSROctetCount_[i]; + return true; + } + } + } + return false; +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildSR(const RtcpContext& ctx) { + for (int i = (RTCP_NUMBER_OF_SR - 2); i >= 0; i--) { + // shift old + last_send_report_[i + 1] = last_send_report_[i]; + last_rtcp_time_[i + 1] = last_rtcp_time_[i]; + lastSRPacketCount_[i+1] = lastSRPacketCount_[i]; + lastSROctetCount_[i+1] = lastSROctetCount_[i]; + } + + last_rtcp_time_[0] = ctx.now_.ToMs(); + last_send_report_[0] = (ctx.now_.seconds() << 16) + (ctx.now_.fractions() >> 16); + lastSRPacketCount_[0] = ctx.feedback_state_.packets_sent; + lastSROctetCount_[0] = ctx.feedback_state_.media_bytes_sent; + + // Timestamp shouldn't be estimated before first media frame. + RTC_DCHECK_GE(last_frame_capture_time_ms_, 0); + // The timestamp of this RTCP packet should be estimated as the timestamp of + // the frame being captured at this moment. We are calculating that + // timestamp as the last frame's timestamp + the time since the last frame + // was captured. + uint32_t rtp_rate = + (audio_ ? kBogusRtpRateForAudioRtcp : kVideoPayloadTypeFrequency) / 1000; + uint32_t rtp_timestamp = + timestamp_offset_ + last_rtp_timestamp_ + + (clock_->TimeInMilliseconds() - last_frame_capture_time_ms_) * rtp_rate; + + rtcp::SenderReport* report = new rtcp::SenderReport(); + report->SetSenderSsrc(ssrc_); + report->SetNtp(ctx.now_); + report->SetRtpTimestamp(rtp_timestamp); + report->SetPacketCount(ctx.feedback_state_.packets_sent); + report->SetOctetCount(ctx.feedback_state_.media_bytes_sent); + report->SetReportBlocks(CreateReportBlocks(ctx.feedback_state_)); + + return std::unique_ptr<rtcp::RtcpPacket>(report); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildSDES( + const RtcpContext& ctx) { + size_t length_cname = cname_.length(); + RTC_CHECK_LT(length_cname, RTCP_CNAME_SIZE); + + rtcp::Sdes* sdes = new rtcp::Sdes(); + sdes->AddCName(ssrc_, cname_); + + for (const auto& it : csrc_cnames_) + RTC_CHECK(sdes->AddCName(it.first, it.second)); + + return std::unique_ptr<rtcp::RtcpPacket>(sdes); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildRR(const RtcpContext& ctx) { + rtcp::ReceiverReport* report = new rtcp::ReceiverReport(); + report->SetSenderSsrc(ssrc_); + report->SetReportBlocks(CreateReportBlocks(ctx.feedback_state_)); + + return std::unique_ptr<rtcp::RtcpPacket>(report); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildPLI(const RtcpContext& ctx) { + rtcp::Pli* pli = new rtcp::Pli(); + pli->SetSenderSsrc(ssrc_); + pli->SetMediaSsrc(remote_ssrc_); + + TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "RTCPSender::PLI"); + ++packet_type_counter_.pli_packets; + TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_PLICount", + ssrc_, packet_type_counter_.pli_packets); + + return std::unique_ptr<rtcp::RtcpPacket>(pli); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildFIR(const RtcpContext& ctx) { + ++sequence_number_fir_; + + rtcp::Fir* fir = new rtcp::Fir(); + fir->SetSenderSsrc(ssrc_); + fir->AddRequestTo(remote_ssrc_, sequence_number_fir_); + + TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "RTCPSender::FIR"); + ++packet_type_counter_.fir_packets; + TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_FIRCount", + ssrc_, packet_type_counter_.fir_packets); + + return std::unique_ptr<rtcp::RtcpPacket>(fir); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildREMB( + const RtcpContext& ctx) { + rtcp::Remb* remb = new rtcp::Remb(); + remb->SetSenderSsrc(ssrc_); + remb->SetBitrateBps(remb_bitrate_); + remb->SetSsrcs(remb_ssrcs_); + + TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "RTCPSender::REMB"); + + return std::unique_ptr<rtcp::RtcpPacket>(remb); +} + +void RTCPSender::SetTargetBitrate(unsigned int target_bitrate) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + tmmbr_send_bps_ = target_bitrate; +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBR( + const RtcpContext& ctx) { + if (ctx.feedback_state_.module == nullptr) + return nullptr; + // Before sending the TMMBR check the received TMMBN, only an owner is + // allowed to raise the bitrate: + // * If the sender is an owner of the TMMBN -> send TMMBR + // * If not an owner but the TMMBR would enter the TMMBN -> send TMMBR + + // get current bounding set from RTCP receiver + bool tmmbr_owner = false; + + // holding critical_section_rtcp_sender_ while calling RTCPreceiver which + // will accuire criticalSectionRTCPReceiver_ is a potental deadlock but + // since RTCPreceiver is not doing the reverse we should be fine + std::vector<rtcp::TmmbItem> candidates = + ctx.feedback_state_.module->BoundingSet(&tmmbr_owner); + + if (!candidates.empty()) { + for (const auto& candidate : candidates) { + if (candidate.bitrate_bps() == tmmbr_send_bps_ && + candidate.packet_overhead() == packet_oh_send_) { + // Do not send the same tuple. + return nullptr; + } + } + if (!tmmbr_owner) { + // Use received bounding set as candidate set. + // Add current tuple. + candidates.emplace_back(ssrc_, tmmbr_send_bps_, packet_oh_send_); + + // Find bounding set. + std::vector<rtcp::TmmbItem> bounding = + TMMBRHelp::FindBoundingSet(std::move(candidates)); + tmmbr_owner = TMMBRHelp::IsOwner(bounding, ssrc_); + if (!tmmbr_owner) { + // Did not enter bounding set, no meaning to send this request. + return nullptr; + } + } + } + + if (!tmmbr_send_bps_) + return nullptr; + + rtcp::Tmmbr* tmmbr = new rtcp::Tmmbr(); + tmmbr->SetSenderSsrc(ssrc_); + rtcp::TmmbItem request; + request.set_ssrc(remote_ssrc_); + request.set_bitrate_bps(tmmbr_send_bps_); + request.set_packet_overhead(packet_oh_send_); + tmmbr->AddTmmbr(request); + + return std::unique_ptr<rtcp::RtcpPacket>(tmmbr); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBN( + const RtcpContext& ctx) { + rtcp::Tmmbn* tmmbn = new rtcp::Tmmbn(); + tmmbn->SetSenderSsrc(ssrc_); + for (const rtcp::TmmbItem& tmmbr : tmmbn_to_send_) { + if (tmmbr.bitrate_bps() > 0) { + tmmbn->AddTmmbr(tmmbr); + } + } + + return std::unique_ptr<rtcp::RtcpPacket>(tmmbn); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildAPP(const RtcpContext& ctx) { + rtcp::App* app = new rtcp::App(); + app->SetSsrc(ssrc_); + app->SetSubType(app_sub_type_); + app->SetName(app_name_); + app->SetData(app_data_.get(), app_length_); + + return std::unique_ptr<rtcp::RtcpPacket>(app); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildNACK( + const RtcpContext& ctx) { + rtcp::Nack* nack = new rtcp::Nack(); + nack->SetSenderSsrc(ssrc_); + nack->SetMediaSsrc(remote_ssrc_); + nack->SetPacketIds(ctx.nack_list_, ctx.nack_size_); + + // Report stats. + NACKStringBuilder stringBuilder; + for (int idx = 0; idx < ctx.nack_size_; ++idx) { + stringBuilder.PushNACK(ctx.nack_list_[idx]); + nack_stats_.ReportRequest(ctx.nack_list_[idx]); + } + packet_type_counter_.nack_requests = nack_stats_.requests(); + packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests(); + + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "RTCPSender::NACK", "nacks", + TRACE_STR_COPY(stringBuilder.GetResult().c_str())); + ++packet_type_counter_.nack_packets; + TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_NACKCount", + ssrc_, packet_type_counter_.nack_packets); + + return std::unique_ptr<rtcp::RtcpPacket>(nack); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildBYE(const RtcpContext& ctx) { + rtcp::Bye* bye = new rtcp::Bye(); + bye->SetSenderSsrc(ssrc_); + bye->SetCsrcs(csrcs_); + + return std::unique_ptr<rtcp::RtcpPacket>(bye); +} + +std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildExtendedReports( + const RtcpContext& ctx) { + std::unique_ptr<rtcp::ExtendedReports> xr(new rtcp::ExtendedReports()); + xr->SetSenderSsrc(ssrc_); + + if (!sending_ && xr_send_receiver_reference_time_enabled_) { + rtcp::Rrtr rrtr; + rrtr.SetNtp(ctx.now_); + xr->SetRrtr(rrtr); + } + + if (ctx.feedback_state_.has_last_xr_rr) { + xr->AddDlrrItem(ctx.feedback_state_.last_xr_rr); + } + + if (video_bitrate_allocation_) { + rtcp::TargetBitrate target_bitrate; + + for (int sl = 0; sl < kMaxSpatialLayers; ++sl) { + for (int tl = 0; tl < kMaxTemporalStreams; ++tl) { + if (video_bitrate_allocation_->HasBitrate(sl, tl)) { + target_bitrate.AddTargetBitrate( + sl, tl, video_bitrate_allocation_->GetBitrate(sl, tl) / 1000); + } + } + } + + xr->SetTargetBitrate(target_bitrate); + video_bitrate_allocation_.reset(); + } + + if (xr_voip_metric_) { + rtcp::VoipMetric voip; + voip.SetMediaSsrc(remote_ssrc_); + voip.SetVoipMetric(*xr_voip_metric_); + xr_voip_metric_.reset(); + + xr->SetVoipMetric(voip); + } + + return std::move(xr); +} + +int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state, + RTCPPacketType packetType, + int32_t nack_size, + const uint16_t* nack_list) { + return SendCompoundRTCP( + feedback_state, std::set<RTCPPacketType>(&packetType, &packetType + 1), + nack_size, nack_list); +} + +int32_t RTCPSender::SendCompoundRTCP( + const FeedbackState& feedback_state, + const std::set<RTCPPacketType>& packet_types, + int32_t nack_size, + const uint16_t* nack_list) { + PacketContainer container(transport_, event_log_); + size_t max_packet_size; + + { + rtc::CritScope lock(&critical_section_rtcp_sender_); + if (method_ == RtcpMode::kOff) { + RTC_LOG(LS_WARNING) << "Can't send rtcp if it is disabled."; + return -1; + } + // Add all flags as volatile. Non volatile entries will not be overwritten. + // All new volatile flags added will be consumed by the end of this call. + SetFlags(packet_types, true); + + // Prevent sending streams to send SR before any media has been sent. + const bool can_calculate_rtp_timestamp = (last_frame_capture_time_ms_ >= 0); + if (!can_calculate_rtp_timestamp) { + bool consumed_sr_flag = ConsumeFlag(kRtcpSr); + bool consumed_report_flag = sending_ && ConsumeFlag(kRtcpReport); + bool sender_report = consumed_report_flag || consumed_sr_flag; + if (sender_report && AllVolatileFlagsConsumed()) { + // This call was for Sender Report and nothing else. + return 0; + } + if (sending_ && method_ == RtcpMode::kCompound) { + // Not allowed to send any RTCP packet without sender report. + return -1; + } + } + + if (packet_type_counter_.first_packet_time_ms == -1) + packet_type_counter_.first_packet_time_ms = clock_->TimeInMilliseconds(); + + // We need to send our NTP even if we haven't received any reports. + RtcpContext context(feedback_state, nack_size, nack_list, + clock_->CurrentNtpTime()); + + PrepareReport(feedback_state); + + std::unique_ptr<rtcp::RtcpPacket> packet_bye; + + auto it = report_flags_.begin(); + while (it != report_flags_.end()) { + auto builder_it = builders_.find(it->type); + RTC_DCHECK(builder_it != builders_.end()) + << "Could not find builder for packet type " << it->type; + if (it->is_volatile) { + report_flags_.erase(it++); + } else { + ++it; + } + + BuilderFunc func = builder_it->second; + std::unique_ptr<rtcp::RtcpPacket> packet = (this->*func)(context); + if (packet.get() == nullptr) + return -1; + // If there is a BYE, don't append now - save it and append it + // at the end later. + if (builder_it->first == kRtcpBye) { + packet_bye = std::move(packet); + } else { + container.Append(packet.release()); + } + } + + // Append the BYE now at the end + if (packet_bye) { + container.Append(packet_bye.release()); + } + + if (packet_type_counter_observer_ != nullptr) { + packet_type_counter_observer_->RtcpPacketTypesCounterUpdated( + remote_ssrc_, packet_type_counter_); + } + + RTC_DCHECK(AllVolatileFlagsConsumed()); + max_packet_size = max_packet_size_; + } + + size_t bytes_sent = container.SendPackets(max_packet_size); + return bytes_sent == 0 ? -1 : 0; +} + +void RTCPSender::PrepareReport(const FeedbackState& feedback_state) { + bool generate_report; + if (IsFlagPresent(kRtcpSr) || IsFlagPresent(kRtcpRr)) { + // Report type already explicitly set, don't automatically populate. + generate_report = true; + RTC_DCHECK(ConsumeFlag(kRtcpReport) == false); + } else { + generate_report = + (ConsumeFlag(kRtcpReport) && method_ == RtcpMode::kReducedSize) || + method_ == RtcpMode::kCompound; + if (generate_report) + SetFlag(sending_ ? kRtcpSr : kRtcpRr, true); + } + + if (IsFlagPresent(kRtcpSr) || (IsFlagPresent(kRtcpRr) && !cname_.empty())) + SetFlag(kRtcpSdes, true); + + if (generate_report) { + if ((!sending_ && xr_send_receiver_reference_time_enabled_) || + feedback_state.has_last_xr_rr || video_bitrate_allocation_) { + SetFlag(kRtcpAnyExtendedReports, true); + } + + // generate next time to send an RTCP report + uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS; + + if (!audio_) { + if (sending_) { + // Calculate bandwidth for video; 360 / send bandwidth in kbit/s. + uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000; + if (send_bitrate_kbit != 0) + minIntervalMs = 360000 / send_bitrate_kbit; + } + if (minIntervalMs > RTCP_INTERVAL_VIDEO_MS) + minIntervalMs = RTCP_INTERVAL_VIDEO_MS; + } + // The interval between RTCP packets is varied randomly over the + // range [1/2,3/2] times the calculated interval. + uint32_t timeToNext = + random_.Rand(minIntervalMs * 1 / 2, minIntervalMs * 3 / 2); + next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + timeToNext; + + // RtcpSender expected to be used for sending either just sender reports + // or just receiver reports. + RTC_DCHECK(!(IsFlagPresent(kRtcpSr) && IsFlagPresent(kRtcpRr))); + } +} + +std::vector<rtcp::ReportBlock> RTCPSender::CreateReportBlocks( + const FeedbackState& feedback_state) { + std::vector<rtcp::ReportBlock> result; + if (!receive_statistics_) + return result; + + // TODO(danilchap): Support sending more than |RTCP_MAX_REPORT_BLOCKS| per + // compound rtcp packet when single rtcp module is used for multiple media + // streams. + result = receive_statistics_->RtcpReportBlocks(RTCP_MAX_REPORT_BLOCKS); + + if (!result.empty() && ((feedback_state.last_rr_ntp_secs != 0) || + (feedback_state.last_rr_ntp_frac != 0))) { + // Get our NTP as late as possible to avoid a race. + uint32_t now = CompactNtp(clock_->CurrentNtpTime()); + + uint32_t receive_time = feedback_state.last_rr_ntp_secs & 0x0000FFFF; + receive_time <<= 16; + receive_time += (feedback_state.last_rr_ntp_frac & 0xffff0000) >> 16; + + uint32_t delay_since_last_sr = now - receive_time; + // TODO(danilchap): Instead of setting same value on all report blocks, + // set only when media_ssrc match sender ssrc of the sender report + // remote times were taken from. + for (auto& report_block : result) { + report_block.SetLastSr(feedback_state.remote_sr); + report_block.SetDelayLastSr(delay_since_last_sr); + } + } + return result; +} + +void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) { + RTC_DCHECK_LE(csrcs.size(), kRtpCsrcSize); + rtc::CritScope lock(&critical_section_rtcp_sender_); + csrcs_ = csrcs; +} + +int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType, + uint32_t name, + const uint8_t* data, + uint16_t length) { + if (length % 4 != 0) { + RTC_LOG(LS_ERROR) << "Failed to SetApplicationSpecificData."; + return -1; + } + rtc::CritScope lock(&critical_section_rtcp_sender_); + + SetFlag(kRtcpApp, true); + app_sub_type_ = subType; + app_name_ = name; + app_data_.reset(new uint8_t[length]); + app_length_ = length; + memcpy(app_data_.get(), data, length); + return 0; +} + +// TODO(sprang): Remove support for VoIP metrics? (Not used in receiver.) +int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + xr_voip_metric_.emplace(*VoIPMetric); + + SetFlag(kRtcpAnyExtendedReports, true); + return 0; +} + +void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + xr_send_receiver_reference_time_enabled_ = enable; +} + +bool RTCPSender::RtcpXrReceiverReferenceTime() const { + rtc::CritScope lock(&critical_section_rtcp_sender_); + return xr_send_receiver_reference_time_enabled_; +} + +void RTCPSender::SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + tmmbn_to_send_ = std::move(bounding_set); + SetFlag(kRtcpTmmbn, true); +} + +void RTCPSender::SetFlag(uint32_t type, bool is_volatile) { + if (type & kRtcpAnyExtendedReports) { + report_flags_.insert(ReportFlag(kRtcpAnyExtendedReports, is_volatile)); + } else { + report_flags_.insert(ReportFlag(type, is_volatile)); + } +} + +void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types, + bool is_volatile) { + for (RTCPPacketType type : types) + SetFlag(type, is_volatile); +} + +bool RTCPSender::IsFlagPresent(uint32_t type) const { + return report_flags_.find(ReportFlag(type, false)) != report_flags_.end(); +} + +bool RTCPSender::ConsumeFlag(uint32_t type, bool forced) { + auto it = report_flags_.find(ReportFlag(type, false)); + if (it == report_flags_.end()) + return false; + if (it->is_volatile || forced) + report_flags_.erase((it)); + return true; +} + +bool RTCPSender::AllVolatileFlagsConsumed() const { + for (const ReportFlag& flag : report_flags_) { + if (flag.is_volatile) + return false; + } + return true; +} + +void RTCPSender::SetVideoBitrateAllocation(const BitrateAllocation& bitrate) { + rtc::CritScope lock(&critical_section_rtcp_sender_); + video_bitrate_allocation_.emplace(bitrate); + SetFlag(kRtcpAnyExtendedReports, true); +} + +bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) { + class Sender : public rtcp::RtcpPacket::PacketReadyCallback { + public: + Sender(Transport* transport, RtcEventLog* event_log) + : transport_(transport), event_log_(event_log), send_failure_(false) {} + + void OnPacketReady(uint8_t* data, size_t length) override { + if (transport_->SendRtcp(data, length)) { + if (event_log_) { + event_log_->Log(rtc::MakeUnique<RtcEventRtcpPacketOutgoing>( + rtc::ArrayView<const uint8_t>(data, length))); + } + } else { + send_failure_ = true; + } + } + + Transport* const transport_; + RtcEventLog* const event_log_; + bool send_failure_; + // TODO(terelius): We would like to + // RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Sender); + // but we can't because of an incorrect warning (C4822) in MVS 2013. + } sender(transport_, event_log_); + + size_t max_packet_size; + { + rtc::CritScope lock(&critical_section_rtcp_sender_); + if (method_ == RtcpMode::kOff) + return false; + max_packet_size = max_packet_size_; + } + + RTC_DCHECK_LE(max_packet_size, IP_PACKET_SIZE); + uint8_t buffer[IP_PACKET_SIZE]; + return packet.BuildExternalBuffer(buffer, max_packet_size, &sender) && + !sender.send_failure_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.h new file mode 100644 index 0000000000..7e6044c063 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.h @@ -0,0 +1,305 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTCP_SENDER_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_SENDER_H_ + +#include <map> +#include <memory> +#include <set> +#include <sstream> +#include <string> +#include <vector> + +#include "api/call/transport.h" +#include "api/optional.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_nack_stats.h" +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" +#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/random.h" +#include "rtc_base/thread_annotations.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class ModuleRtpRtcpImpl; +class RtcEventLog; + +class NACKStringBuilder { + public: + NACKStringBuilder(); + ~NACKStringBuilder(); + + void PushNACK(uint16_t nack); + std::string GetResult(); + + private: + std::ostringstream stream_; + int count_; + uint16_t prevNack_; + bool consecutive_; +}; + +class RTCPSender { + public: + struct FeedbackState { + FeedbackState(); + + uint32_t packets_sent; + size_t media_bytes_sent; + uint32_t send_bitrate; + + uint32_t last_rr_ntp_secs; + uint32_t last_rr_ntp_frac; + uint32_t remote_sr; + + bool has_last_xr_rr; + rtcp::ReceiveTimeInfo last_xr_rr; + + // Used when generating TMMBR. + ModuleRtpRtcpImpl* module; + }; + + RTCPSender(bool audio, + Clock* clock, + ReceiveStatisticsProvider* receive_statistics, + RtcpPacketTypeCounterObserver* packet_type_counter_observer, + RtcEventLog* event_log, + Transport* outgoing_transport); + virtual ~RTCPSender(); + + RtcpMode Status() const; + void SetRTCPStatus(RtcpMode method); + + bool Sending() const; + int32_t SetSendingStatus(const FeedbackState& feedback_state, + bool enabled); // combine the functions + + int32_t SetNackStatus(bool enable); + + void SetTimestampOffset(uint32_t timestamp_offset); + + void SetLastRtpTime(uint32_t rtp_timestamp, int64_t capture_time_ms); + + uint32_t SSRC() const; + + void SetSSRC(uint32_t ssrc); + + void SetRemoteSSRC(uint32_t ssrc); + + int32_t SetCNAME(const char* cName); + + int32_t AddMixedCNAME(uint32_t SSRC, const char* c_name); + + int32_t RemoveMixedCNAME(uint32_t SSRC); + + bool GetSendReportMetadata(const uint32_t sendReport, + uint64_t *timeOfSend, + uint32_t *packetCount, + uint64_t *octetCount); + + bool TimeToSendRTCPReport(bool sendKeyframeBeforeRTP = false) const; + + int32_t SendRTCP(const FeedbackState& feedback_state, + RTCPPacketType packetType, + int32_t nackSize = 0, + const uint16_t* nackList = 0); + + int32_t SendCompoundRTCP(const FeedbackState& feedback_state, + const std::set<RTCPPacketType>& packetTypes, + int32_t nackSize = 0, + const uint16_t* nackList = 0); + + void SetRemb(uint32_t bitrate, const std::vector<uint32_t>& ssrcs); + + void UnsetRemb(); + + bool TMMBR() const; + + void SetTMMBRStatus(bool enable); + + void SetMaxRtpPacketSize(size_t max_packet_size); + + void SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set); + + int32_t SetApplicationSpecificData(uint8_t subType, + uint32_t name, + const uint8_t* data, + uint16_t length); + int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric); + + void SendRtcpXrReceiverReferenceTime(bool enable); + + bool RtcpXrReceiverReferenceTime() const; + + void SetCsrcs(const std::vector<uint32_t>& csrcs); + + void SetTargetBitrate(unsigned int target_bitrate); + void SetVideoBitrateAllocation(const BitrateAllocation& bitrate); + bool SendFeedbackPacket(const rtcp::TransportFeedback& packet); + + private: + class RtcpContext; + + // Determine which RTCP messages should be sent and setup flags. + void PrepareReport(const FeedbackState& feedback_state) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + + std::vector<rtcp::ReportBlock> CreateReportBlocks( + const FeedbackState& feedback_state) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + + std::unique_ptr<rtcp::RtcpPacket> BuildSR(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildRR(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildSDES(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildPLI(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildREMB(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildTMMBR(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildTMMBN(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildAPP(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildExtendedReports( + const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildBYE(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildFIR(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + std::unique_ptr<rtcp::RtcpPacket> BuildNACK(const RtcpContext& context) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + + private: + const bool audio_; + Clock* const clock_; + Random random_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + RtcpMode method_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + RtcEventLog* const event_log_; + Transport* const transport_; + + rtc::CriticalSection critical_section_rtcp_sender_; + bool using_nack_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + bool sending_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + int64_t next_time_to_send_rtcp_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + uint32_t timestamp_offset_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + int64_t last_frame_capture_time_ms_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + uint32_t ssrc_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + // SSRC that we receive on our RTP channel + uint32_t remote_ssrc_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + std::string cname_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + ReceiveStatisticsProvider* receive_statistics_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + std::map<uint32_t, std::string> csrc_cnames_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + + // Sent + uint32_t last_send_report_[RTCP_NUMBER_OF_SR] RTC_GUARDED_BY( + critical_section_rtcp_sender_); // allow packet loss and RTT above 1 sec + int64_t last_rtcp_time_[RTCP_NUMBER_OF_SR] RTC_GUARDED_BY( + critical_section_rtcp_sender_); + uint32_t lastSRPacketCount_[RTCP_NUMBER_OF_SR] RTC_GUARDED_BY( + critical_section_rtcp_sender_); + uint64_t lastSROctetCount_[RTCP_NUMBER_OF_SR] RTC_GUARDED_BY( + critical_section_rtcp_sender_); + + // send CSRCs + std::vector<uint32_t> csrcs_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + // Full intra request + uint8_t sequence_number_fir_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + // REMB + uint32_t remb_bitrate_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + std::vector<uint32_t> remb_ssrcs_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + + std::vector<rtcp::TmmbItem> tmmbn_to_send_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + uint32_t tmmbr_send_bps_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + uint32_t packet_oh_send_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + size_t max_packet_size_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + // APP + uint8_t app_sub_type_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + uint32_t app_name_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + std::unique_ptr<uint8_t[]> app_data_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + uint16_t app_length_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + // True if sending of XR Receiver reference time report is enabled. + bool xr_send_receiver_reference_time_enabled_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + + // XR VoIP metric + rtc::Optional<RTCPVoIPMetric> xr_voip_metric_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + + RtcpPacketTypeCounterObserver* const packet_type_counter_observer_; + RtcpPacketTypeCounter packet_type_counter_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + + RtcpNackStats nack_stats_ RTC_GUARDED_BY(critical_section_rtcp_sender_); + + rtc::Optional<BitrateAllocation> video_bitrate_allocation_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + + void SetFlag(uint32_t type, bool is_volatile) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + void SetFlags(const std::set<RTCPPacketType>& types, bool is_volatile) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + bool IsFlagPresent(uint32_t type) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + bool ConsumeFlag(uint32_t type, bool forced = false) + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + bool AllVolatileFlagsConsumed() const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_); + struct ReportFlag { + ReportFlag(uint32_t type, bool is_volatile) + : type(type), is_volatile(is_volatile) {} + bool operator<(const ReportFlag& flag) const { return type < flag.type; } + bool operator==(const ReportFlag& flag) const { return type == flag.type; } + const uint32_t type; + const bool is_volatile; + }; + + std::set<ReportFlag> report_flags_ + RTC_GUARDED_BY(critical_section_rtcp_sender_); + + typedef std::unique_ptr<rtcp::RtcpPacket> (RTCPSender::*BuilderFunc)( + const RtcpContext&); + // Map from RTCPPacketType to builder. + std::map<uint32_t, BuilderFunc> builders_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTCPSender); +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_SENDER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc new file mode 100644 index 0000000000..9ba7689425 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc @@ -0,0 +1,826 @@ +/* + * 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 <memory> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "modules/rtp_rtcp/source/rtcp_sender.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h" +#include "rtc_base/rate_limiter.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/mock_transport.h" +#include "test/rtcp_packet_parser.h" + +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Invoke; + +namespace webrtc { + +TEST(NACKStringBuilderTest, TestCase1) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(7); + builder.PushNACK(9); + builder.PushNACK(10); + builder.PushNACK(11); + builder.PushNACK(12); + builder.PushNACK(15); + builder.PushNACK(18); + builder.PushNACK(19); + EXPECT_EQ(std::string("5,7,9-12,15,18-19"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase2) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(6); + builder.PushNACK(7); + builder.PushNACK(9); + builder.PushNACK(10); + builder.PushNACK(11); + builder.PushNACK(12); + builder.PushNACK(15); + builder.PushNACK(18); + builder.PushNACK(19); + EXPECT_EQ(std::string("5-7,9-12,15,18-19"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase3) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(7); + builder.PushNACK(9); + builder.PushNACK(10); + builder.PushNACK(11); + builder.PushNACK(12); + builder.PushNACK(15); + builder.PushNACK(18); + builder.PushNACK(19); + builder.PushNACK(21); + EXPECT_EQ(std::string("5,7,9-12,15,18-19,21"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase4) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(7); + builder.PushNACK(8); + builder.PushNACK(9); + builder.PushNACK(10); + builder.PushNACK(11); + builder.PushNACK(12); + builder.PushNACK(15); + builder.PushNACK(18); + builder.PushNACK(19); + EXPECT_EQ(std::string("5,7-12,15,18-19"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase5) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(7); + builder.PushNACK(9); + builder.PushNACK(10); + builder.PushNACK(11); + builder.PushNACK(12); + builder.PushNACK(15); + builder.PushNACK(16); + builder.PushNACK(18); + builder.PushNACK(19); + EXPECT_EQ(std::string("5,7,9-12,15-16,18-19"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase6) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(7); + builder.PushNACK(9); + builder.PushNACK(10); + builder.PushNACK(11); + builder.PushNACK(12); + builder.PushNACK(15); + builder.PushNACK(16); + builder.PushNACK(17); + builder.PushNACK(18); + builder.PushNACK(19); + EXPECT_EQ(std::string("5,7,9-12,15-19"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase7) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(6); + builder.PushNACK(7); + builder.PushNACK(8); + builder.PushNACK(11); + builder.PushNACK(12); + builder.PushNACK(13); + builder.PushNACK(14); + builder.PushNACK(15); + EXPECT_EQ(std::string("5-8,11-15"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase8) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(7); + builder.PushNACK(9); + builder.PushNACK(11); + builder.PushNACK(15); + builder.PushNACK(17); + builder.PushNACK(19); + EXPECT_EQ(std::string("5,7,9,11,15,17,19"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase9) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(6); + builder.PushNACK(7); + builder.PushNACK(8); + builder.PushNACK(9); + builder.PushNACK(10); + builder.PushNACK(11); + builder.PushNACK(12); + EXPECT_EQ(std::string("5-12"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase10) { + NACKStringBuilder builder; + builder.PushNACK(5); + EXPECT_EQ(std::string("5"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase11) { + NACKStringBuilder builder; + EXPECT_EQ(std::string(""), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase12) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(6); + EXPECT_EQ(std::string("5-6"), builder.GetResult()); +} + +TEST(NACKStringBuilderTest, TestCase13) { + NACKStringBuilder builder; + builder.PushNACK(5); + builder.PushNACK(6); + builder.PushNACK(9); + EXPECT_EQ(std::string("5-6,9"), builder.GetResult()); +} + +class RtcpPacketTypeCounterObserverImpl : public RtcpPacketTypeCounterObserver { + public: + RtcpPacketTypeCounterObserverImpl() : ssrc_(0) {} + virtual ~RtcpPacketTypeCounterObserverImpl() {} + void RtcpPacketTypesCounterUpdated( + uint32_t ssrc, + const RtcpPacketTypeCounter& packet_counter) override { + ssrc_ = ssrc; + counter_ = packet_counter; + } + uint32_t ssrc_; + RtcpPacketTypeCounter counter_; +}; + +class TestTransport : public Transport, + public RtpData { + public: + TestTransport() {} + + bool SendRtp(const uint8_t* /*data*/, + size_t /*len*/, + const PacketOptions& options) override { + return false; + } + bool SendRtcp(const uint8_t* data, size_t len) override { + parser_.Parse(data, len); + return true; + } + int OnReceivedPayloadData(const uint8_t* payload_data, + size_t payload_size, + const WebRtcRTPHeader* rtp_header) override { + return 0; + } + test::RtcpPacketParser parser_; +}; + +namespace { +static const uint32_t kSenderSsrc = 0x11111111; +static const uint32_t kRemoteSsrc = 0x22222222; +static const uint32_t kStartRtpTimestamp = 0x34567; +static const uint32_t kRtpTimestamp = 0x45678; +} + +class RtcpSenderTest : public ::testing::Test { + protected: + RtcpSenderTest() + : clock_(1335900000), + receive_statistics_(ReceiveStatistics::Create(&clock_)), + retransmission_rate_limiter_(&clock_, 1000) { + RtpRtcp::Configuration configuration; + configuration.audio = false; + configuration.clock = &clock_; + configuration.outgoing_transport = &test_transport_; + configuration.retransmission_rate_limiter = &retransmission_rate_limiter_; + + rtp_rtcp_impl_.reset(new ModuleRtpRtcpImpl(configuration)); + rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(), + nullptr, nullptr, &test_transport_)); + rtcp_sender_->SetSSRC(kSenderSsrc); + rtcp_sender_->SetRemoteSSRC(kRemoteSsrc); + rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp); + rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds()); + } + + void InsertIncomingPacket(uint32_t remote_ssrc, uint16_t seq_num) { + RTPHeader header; + header.ssrc = remote_ssrc; + header.sequenceNumber = seq_num; + header.timestamp = 12345; + header.headerLength = 12; + size_t kPacketLength = 100; + receive_statistics_->IncomingPacket(header, kPacketLength, false); + } + + test::RtcpPacketParser* parser() { return &test_transport_.parser_; } + + RTCPSender::FeedbackState feedback_state() { + return rtp_rtcp_impl_->GetFeedbackState(); + } + + SimulatedClock clock_; + TestTransport test_transport_; + std::unique_ptr<ReceiveStatistics> receive_statistics_; + std::unique_ptr<ModuleRtpRtcpImpl> rtp_rtcp_impl_; + std::unique_ptr<RTCPSender> rtcp_sender_; + RateLimiter retransmission_rate_limiter_; +}; + +TEST_F(RtcpSenderTest, SetRtcpStatus) { + EXPECT_EQ(RtcpMode::kOff, rtcp_sender_->Status()); + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(RtcpMode::kReducedSize, rtcp_sender_->Status()); +} + +TEST_F(RtcpSenderTest, SetSendingStatus) { + EXPECT_FALSE(rtcp_sender_->Sending()); + EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true)); + EXPECT_TRUE(rtcp_sender_->Sending()); +} + +TEST_F(RtcpSenderTest, NoPacketSentIfOff) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kOff); + EXPECT_EQ(-1, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr)); +} + +TEST_F(RtcpSenderTest, SendSr) { + const uint32_t kPacketCount = 0x12345; + const uint32_t kOctetCount = 0x23456; + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState(); + rtcp_sender_->SetSendingStatus(feedback_state, true); + feedback_state.packets_sent = kPacketCount; + feedback_state.media_bytes_sent = kOctetCount; + NtpTime ntp = clock_.CurrentNtpTime(); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpSr)); + EXPECT_EQ(1, parser()->sender_report()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->sender_report()->sender_ssrc()); + EXPECT_EQ(ntp, parser()->sender_report()->ntp()); + EXPECT_EQ(kPacketCount, parser()->sender_report()->sender_packet_count()); + EXPECT_EQ(kOctetCount, parser()->sender_report()->sender_octet_count()); + EXPECT_EQ(kStartRtpTimestamp + kRtpTimestamp, + parser()->sender_report()->rtp_timestamp()); + EXPECT_EQ(0U, parser()->sender_report()->report_blocks().size()); +} + +TEST_F(RtcpSenderTest, DoNotSendSrBeforeRtp) { + rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(), + nullptr, nullptr, &test_transport_)); + rtcp_sender_->SetSSRC(kSenderSsrc); + rtcp_sender_->SetRemoteSSRC(kRemoteSsrc); + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + rtcp_sender_->SetSendingStatus(feedback_state(), true); + + // Sender Report shouldn't be send as an SR nor as a Report. + rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr); + EXPECT_EQ(0, parser()->sender_report()->num_packets()); + rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport); + EXPECT_EQ(0, parser()->sender_report()->num_packets()); + // Other packets (e.g. Pli) are allowed, even if useless. + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli)); + EXPECT_EQ(1, parser()->pli()->num_packets()); +} + +TEST_F(RtcpSenderTest, DoNotSendCompundBeforeRtp) { + rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(), + nullptr, nullptr, &test_transport_)); + rtcp_sender_->SetSSRC(kSenderSsrc); + rtcp_sender_->SetRemoteSSRC(kRemoteSsrc); + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + rtcp_sender_->SetSendingStatus(feedback_state(), true); + + // In compound mode no packets are allowed (e.g. Pli) because compound mode + // should start with Sender Report. + EXPECT_EQ(-1, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli)); + EXPECT_EQ(0, parser()->pli()->num_packets()); +} + +TEST_F(RtcpSenderTest, SendRr) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr)); + EXPECT_EQ(1, parser()->receiver_report()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc()); + EXPECT_EQ(0U, parser()->receiver_report()->report_blocks().size()); +} + +TEST_F(RtcpSenderTest, SendRrWithOneReportBlock) { + const uint16_t kSeqNum = 11111; + InsertIncomingPacket(kRemoteSsrc, kSeqNum); + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr)); + EXPECT_EQ(1, parser()->receiver_report()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc()); + ASSERT_EQ(1U, parser()->receiver_report()->report_blocks().size()); + const rtcp::ReportBlock& rb = parser()->receiver_report()->report_blocks()[0]; + EXPECT_EQ(kRemoteSsrc, rb.source_ssrc()); + EXPECT_EQ(0U, rb.fraction_lost()); + EXPECT_EQ(0U, rb.cumulative_lost()); + EXPECT_EQ(kSeqNum, rb.extended_high_seq_num()); +} + +TEST_F(RtcpSenderTest, SendRrWithTwoReportBlocks) { + const uint16_t kSeqNum = 11111; + InsertIncomingPacket(kRemoteSsrc, kSeqNum); + InsertIncomingPacket(kRemoteSsrc + 1, kSeqNum + 1); + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr)); + EXPECT_EQ(1, parser()->receiver_report()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc()); + EXPECT_EQ(2U, parser()->receiver_report()->report_blocks().size()); + EXPECT_EQ(kRemoteSsrc, + parser()->receiver_report()->report_blocks()[0].source_ssrc()); + EXPECT_EQ(kRemoteSsrc + 1, + parser()->receiver_report()->report_blocks()[1].source_ssrc()); +} + +TEST_F(RtcpSenderTest, SendSdes) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host")); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSdes)); + EXPECT_EQ(1, parser()->sdes()->num_packets()); + EXPECT_EQ(1U, parser()->sdes()->chunks().size()); + EXPECT_EQ(kSenderSsrc, parser()->sdes()->chunks()[0].ssrc); + EXPECT_EQ("alice@host", parser()->sdes()->chunks()[0].cname); +} + +TEST_F(RtcpSenderTest, SendSdesWithMaxChunks) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host")); + const char cname[] = "smith@host"; + for (size_t i = 0; i < 30; ++i) { + const uint32_t csrc = 0x1234 + i; + EXPECT_EQ(0, rtcp_sender_->AddMixedCNAME(csrc, cname)); + } + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSdes)); + EXPECT_EQ(1, parser()->sdes()->num_packets()); + EXPECT_EQ(31U, parser()->sdes()->chunks().size()); +} + +TEST_F(RtcpSenderTest, SdesIncludedInCompoundPacket) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host")); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(1, parser()->receiver_report()->num_packets()); + EXPECT_EQ(1, parser()->sdes()->num_packets()); + EXPECT_EQ(1U, parser()->sdes()->chunks().size()); +} + +TEST_F(RtcpSenderTest, SendBye) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye)); + EXPECT_EQ(1, parser()->bye()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc()); +} + +TEST_F(RtcpSenderTest, StopSendingTriggersBye) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true)); + EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false)); + EXPECT_EQ(1, parser()->bye()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc()); +} + +TEST_F(RtcpSenderTest, SendApp) { + const uint8_t kSubType = 30; + uint32_t name = 'n' << 24; + name += 'a' << 16; + name += 'm' << 8; + name += 'e'; + const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'}; + EXPECT_EQ(0, rtcp_sender_->SetApplicationSpecificData(kSubType, name, kData, + sizeof(kData))); + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpApp)); + EXPECT_EQ(1, parser()->app()->num_packets()); + EXPECT_EQ(kSubType, parser()->app()->sub_type()); + EXPECT_EQ(name, parser()->app()->name()); + EXPECT_EQ(sizeof(kData), parser()->app()->data_size()); + EXPECT_EQ(0, memcmp(kData, parser()->app()->data(), sizeof(kData))); +} + +TEST_F(RtcpSenderTest, SendEmptyApp) { + const uint8_t kSubType = 30; + const uint32_t kName = 0x6E616D65; + + EXPECT_EQ( + 0, rtcp_sender_->SetApplicationSpecificData(kSubType, kName, nullptr, 0)); + + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpApp)); + EXPECT_EQ(1, parser()->app()->num_packets()); + EXPECT_EQ(kSubType, parser()->app()->sub_type()); + EXPECT_EQ(kName, parser()->app()->name()); + EXPECT_EQ(0U, parser()->app()->data_size()); +} + +TEST_F(RtcpSenderTest, SetInvalidApplicationSpecificData) { + const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't'}; + const uint16_t kInvalidDataLength = sizeof(kData) / sizeof(kData[0]); + EXPECT_EQ(-1, rtcp_sender_->SetApplicationSpecificData( + 0, 0, kData, kInvalidDataLength)); // Should by multiple of 4. +} + +TEST_F(RtcpSenderTest, SendFir) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir)); + EXPECT_EQ(1, parser()->fir()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->fir()->sender_ssrc()); + EXPECT_EQ(1U, parser()->fir()->requests().size()); + EXPECT_EQ(kRemoteSsrc, parser()->fir()->requests()[0].ssrc); + uint8_t seq = parser()->fir()->requests()[0].seq_nr; + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir)); + EXPECT_EQ(2, parser()->fir()->num_packets()); + EXPECT_EQ(seq + 1, parser()->fir()->requests()[0].seq_nr); +} + +TEST_F(RtcpSenderTest, SendPli) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli)); + EXPECT_EQ(1, parser()->pli()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->pli()->sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, parser()->pli()->media_ssrc()); +} + +TEST_F(RtcpSenderTest, SendNack) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + const uint16_t kList[] = {0, 1, 16}; + const int32_t kListLength = sizeof(kList) / sizeof(kList[0]); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpNack, kListLength, + kList)); + EXPECT_EQ(1, parser()->nack()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->nack()->sender_ssrc()); + EXPECT_EQ(kRemoteSsrc, parser()->nack()->media_ssrc()); + EXPECT_THAT(parser()->nack()->packet_ids(), ElementsAre(0, 1, 16)); +} + +TEST_F(RtcpSenderTest, RembNotIncludedBeforeSet) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + + rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr); + + ASSERT_EQ(1, parser()->receiver_report()->num_packets()); + EXPECT_EQ(0, parser()->remb()->num_packets()); +} + +TEST_F(RtcpSenderTest, RembNotIncludedAfterUnset) { + const uint64_t kBitrate = 261011; + const std::vector<uint32_t> kSsrcs = {kRemoteSsrc, kRemoteSsrc + 1}; + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + rtcp_sender_->SetRemb(kBitrate, kSsrcs); + rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr); + ASSERT_EQ(1, parser()->receiver_report()->num_packets()); + EXPECT_EQ(1, parser()->remb()->num_packets()); + + // Turn off REMB. rtcp_sender no longer should send it. + rtcp_sender_->UnsetRemb(); + rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr); + ASSERT_EQ(2, parser()->receiver_report()->num_packets()); + EXPECT_EQ(1, parser()->remb()->num_packets()); +} + +TEST_F(RtcpSenderTest, SendRemb) { + const uint64_t kBitrate = 261011; + const std::vector<uint32_t> kSsrcs = {kRemoteSsrc, kRemoteSsrc + 1}; + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + rtcp_sender_->SetRemb(kBitrate, kSsrcs); + + rtcp_sender_->SendRTCP(feedback_state(), kRtcpRemb); + + EXPECT_EQ(1, parser()->remb()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->remb()->sender_ssrc()); + EXPECT_EQ(kBitrate, parser()->remb()->bitrate_bps()); + EXPECT_THAT(parser()->remb()->ssrcs(), + ElementsAre(kRemoteSsrc, kRemoteSsrc + 1)); +} + +TEST_F(RtcpSenderTest, RembIncludedInEachCompoundPacketAfterSet) { + const int kBitrate = 261011; + const std::vector<uint32_t> kSsrcs = {kRemoteSsrc, kRemoteSsrc + 1}; + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + rtcp_sender_->SetRemb(kBitrate, kSsrcs); + + rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport); + EXPECT_EQ(1, parser()->remb()->num_packets()); + // REMB should be included in each compound packet. + rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport); + EXPECT_EQ(2, parser()->remb()->num_packets()); +} + +TEST_F(RtcpSenderTest, SendXrWithVoipMetric) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + RTCPVoIPMetric metric; + metric.lossRate = 1; + metric.discardRate = 2; + metric.burstDensity = 3; + metric.gapDensity = 4; + metric.burstDuration = 0x1111; + metric.gapDuration = 0x2222; + metric.roundTripDelay = 0x3333; + metric.endSystemDelay = 0x4444; + metric.signalLevel = 5; + metric.noiseLevel = 6; + metric.RERL = 7; + metric.Gmin = 8; + metric.Rfactor = 9; + metric.extRfactor = 10; + metric.MOSLQ = 11; + metric.MOSCQ = 12; + metric.RXconfig = 13; + metric.JBnominal = 0x5555; + metric.JBmax = 0x6666; + metric.JBabsMax = 0x7777; + EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric)); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpXrVoipMetric)); + EXPECT_EQ(1, parser()->xr()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc()); + ASSERT_TRUE(parser()->xr()->voip_metric()); + EXPECT_EQ(kRemoteSsrc, parser()->xr()->voip_metric()->ssrc()); + const auto& parsed_metric = parser()->xr()->voip_metric()->voip_metric(); + EXPECT_EQ(metric.lossRate, parsed_metric.lossRate); + EXPECT_EQ(metric.discardRate, parsed_metric.discardRate); + EXPECT_EQ(metric.burstDensity, parsed_metric.burstDensity); + EXPECT_EQ(metric.gapDensity, parsed_metric.gapDensity); + EXPECT_EQ(metric.burstDuration, parsed_metric.burstDuration); + EXPECT_EQ(metric.gapDuration, parsed_metric.gapDuration); + EXPECT_EQ(metric.roundTripDelay, parsed_metric.roundTripDelay); + EXPECT_EQ(metric.endSystemDelay, parsed_metric.endSystemDelay); + EXPECT_EQ(metric.signalLevel, parsed_metric.signalLevel); + EXPECT_EQ(metric.noiseLevel, parsed_metric.noiseLevel); + EXPECT_EQ(metric.RERL, parsed_metric.RERL); + EXPECT_EQ(metric.Gmin, parsed_metric.Gmin); + EXPECT_EQ(metric.Rfactor, parsed_metric.Rfactor); + EXPECT_EQ(metric.extRfactor, parsed_metric.extRfactor); + EXPECT_EQ(metric.MOSLQ, parsed_metric.MOSLQ); + EXPECT_EQ(metric.MOSCQ, parsed_metric.MOSCQ); + EXPECT_EQ(metric.RXconfig, parsed_metric.RXconfig); + EXPECT_EQ(metric.JBnominal, parsed_metric.JBnominal); + EXPECT_EQ(metric.JBmax, parsed_metric.JBmax); + EXPECT_EQ(metric.JBabsMax, parsed_metric.JBabsMax); +} + +TEST_F(RtcpSenderTest, SendXrWithDlrr) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState(); + feedback_state.has_last_xr_rr = true; + rtcp::ReceiveTimeInfo last_xr_rr; + last_xr_rr.ssrc = 0x11111111; + last_xr_rr.last_rr = 0x22222222; + last_xr_rr.delay_since_last_rr = 0x33333333; + feedback_state.last_xr_rr = last_xr_rr; + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport)); + EXPECT_EQ(1, parser()->xr()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc()); + EXPECT_EQ(1U, parser()->xr()->dlrr().sub_blocks().size()); + EXPECT_EQ(last_xr_rr.ssrc, parser()->xr()->dlrr().sub_blocks()[0].ssrc); + EXPECT_EQ(last_xr_rr.last_rr, parser()->xr()->dlrr().sub_blocks()[0].last_rr); + EXPECT_EQ(last_xr_rr.delay_since_last_rr, + parser()->xr()->dlrr().sub_blocks()[0].delay_since_last_rr); +} + +TEST_F(RtcpSenderTest, SendXrWithRrtr) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false)); + rtcp_sender_->SendRtcpXrReceiverReferenceTime(true); + NtpTime ntp = clock_.CurrentNtpTime(); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(1, parser()->xr()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc()); + EXPECT_FALSE(parser()->xr()->dlrr()); + EXPECT_FALSE(parser()->xr()->voip_metric()); + ASSERT_TRUE(parser()->xr()->rrtr()); + EXPECT_EQ(ntp, parser()->xr()->rrtr()->ntp()); +} + +TEST_F(RtcpSenderTest, TestNoXrRrtrSentIfSending) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true)); + rtcp_sender_->SendRtcpXrReceiverReferenceTime(true); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(0, parser()->xr()->num_packets()); +} + +TEST_F(RtcpSenderTest, TestNoXrRrtrSentIfNotEnabled) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false)); + rtcp_sender_->SendRtcpXrReceiverReferenceTime(false); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(0, parser()->xr()->num_packets()); +} + +TEST_F(RtcpSenderTest, TestRegisterRtcpPacketTypeObserver) { + RtcpPacketTypeCounterObserverImpl observer; + rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(), + &observer, nullptr, &test_transport_)); + rtcp_sender_->SetRemoteSSRC(kRemoteSsrc); + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli)); + EXPECT_EQ(1, parser()->pli()->num_packets()); + EXPECT_EQ(kRemoteSsrc, observer.ssrc_); + EXPECT_EQ(1U, observer.counter_.pli_packets); + EXPECT_EQ(clock_.TimeInMilliseconds(), + observer.counter_.first_packet_time_ms); +} + +TEST_F(RtcpSenderTest, SendTmmbr) { + const unsigned int kBitrateBps = 312000; + rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize); + rtcp_sender_->SetTargetBitrate(kBitrateBps); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpTmmbr)); + EXPECT_EQ(1, parser()->tmmbr()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->tmmbr()->sender_ssrc()); + EXPECT_EQ(1U, parser()->tmmbr()->requests().size()); + EXPECT_EQ(kBitrateBps, parser()->tmmbr()->requests()[0].bitrate_bps()); + // TODO(asapersson): tmmbr_item()->Overhead() looks broken, always zero. +} + +TEST_F(RtcpSenderTest, TmmbrIncludedInCompoundPacketIfEnabled) { + const unsigned int kBitrateBps = 312000; + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_FALSE(rtcp_sender_->TMMBR()); + rtcp_sender_->SetTMMBRStatus(true); + EXPECT_TRUE(rtcp_sender_->TMMBR()); + rtcp_sender_->SetTargetBitrate(kBitrateBps); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(1, parser()->tmmbr()->num_packets()); + EXPECT_EQ(1U, parser()->tmmbr()->requests().size()); + // TMMBR should be included in each compound packet. + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(2, parser()->tmmbr()->num_packets()); + + rtcp_sender_->SetTMMBRStatus(false); + EXPECT_FALSE(rtcp_sender_->TMMBR()); +} + +TEST_F(RtcpSenderTest, SendTmmbn) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + rtcp_sender_->SetSendingStatus(feedback_state(), true); + std::vector<rtcp::TmmbItem> bounding_set; + const uint32_t kBitrateBps = 32768000; + const uint32_t kPacketOh = 40; + const uint32_t kSourceSsrc = 12345; + const rtcp::TmmbItem tmmbn(kSourceSsrc, kBitrateBps, kPacketOh); + bounding_set.push_back(tmmbn); + rtcp_sender_->SetTmmbn(bounding_set); + + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr)); + EXPECT_EQ(1, parser()->sender_report()->num_packets()); + EXPECT_EQ(1, parser()->tmmbn()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->tmmbn()->sender_ssrc()); + EXPECT_EQ(1U, parser()->tmmbn()->items().size()); + EXPECT_EQ(kBitrateBps, parser()->tmmbn()->items()[0].bitrate_bps()); + EXPECT_EQ(kPacketOh, parser()->tmmbn()->items()[0].packet_overhead()); + EXPECT_EQ(kSourceSsrc, parser()->tmmbn()->items()[0].ssrc()); +} + +// This test is written to verify actual behaviour. It does not seem +// to make much sense to send an empty TMMBN, since there is no place +// to put an actual limit here. It's just information that no limit +// is set, which is kind of the starting assumption. +// See http://code.google.com/p/webrtc/issues/detail?id=468 for one +// situation where this caused confusion. +TEST_F(RtcpSenderTest, SendsTmmbnIfSetAndEmpty) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + rtcp_sender_->SetSendingStatus(feedback_state(), true); + std::vector<rtcp::TmmbItem> bounding_set; + rtcp_sender_->SetTmmbn(bounding_set); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr)); + EXPECT_EQ(1, parser()->sender_report()->num_packets()); + EXPECT_EQ(1, parser()->tmmbn()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->tmmbn()->sender_ssrc()); + EXPECT_EQ(0U, parser()->tmmbn()->items().size()); +} + +TEST_F(RtcpSenderTest, SendCompoundPliRemb) { + const int kBitrate = 261011; + std::vector<uint32_t> ssrcs; + ssrcs.push_back(kRemoteSsrc); + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + rtcp_sender_->SetRemb(kBitrate, ssrcs); + std::set<RTCPPacketType> packet_types; + packet_types.insert(kRtcpRemb); + packet_types.insert(kRtcpPli); + EXPECT_EQ(0, rtcp_sender_->SendCompoundRTCP(feedback_state(), packet_types)); + EXPECT_EQ(1, parser()->remb()->num_packets()); + EXPECT_EQ(1, parser()->pli()->num_packets()); +} + +// This test is written to verify that BYE is always the last packet +// type in a RTCP compoud packet. The rtcp_sender_ is recreated with +// mock_transport, which is used to check for whether BYE at the end +// of a RTCP compound packet. +TEST_F(RtcpSenderTest, ByeMustBeLast) { + MockTransport mock_transport; + EXPECT_CALL(mock_transport, SendRtcp(_, _)) + .WillOnce(Invoke([](const uint8_t* data, size_t len) { + const uint8_t* next_packet = data; + const uint8_t* const packet_end = data + len; + rtcp::CommonHeader packet; + while (next_packet < packet_end) { + EXPECT_TRUE(packet.Parse(next_packet, packet_end - next_packet)); + next_packet = packet.NextPacket(); + if (packet.type() == rtcp::Bye::kPacketType) // Main test expectation. + EXPECT_EQ(0, packet_end - next_packet) + << "Bye packet should be last in a compound RTCP packet."; + if (next_packet == packet_end) // Validate test was set correctly. + EXPECT_EQ(packet.type(), rtcp::Bye::kPacketType) + << "Last packet in this test expected to be Bye."; + } + + return true; + })); + + // Re-configure rtcp_sender_ with mock_transport_ + rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(), + nullptr, nullptr, &mock_transport)); + rtcp_sender_->SetSSRC(kSenderSsrc); + rtcp_sender_->SetRemoteSSRC(kRemoteSsrc); + rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp); + rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds()); + + // Set up XR VoIP metric to be included with BYE + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + RTCPVoIPMetric metric; + EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric)); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye)); +} + +TEST_F(RtcpSenderTest, SendXrWithTargetBitrate) { + rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound); + const size_t kNumSpatialLayers = 2; + const size_t kNumTemporalLayers = 2; + BitrateAllocation allocation; + for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) { + uint32_t start_bitrate_bps = (sl + 1) * 100000; + for (size_t tl = 0; tl < kNumTemporalLayers; ++tl) + allocation.SetBitrate(sl, tl, start_bitrate_bps + (tl * 20000)); + } + rtcp_sender_->SetVideoBitrateAllocation(allocation); + + EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(1, parser()->xr()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc()); + const rtc::Optional<rtcp::TargetBitrate>& target_bitrate = + parser()->xr()->target_bitrate(); + ASSERT_TRUE(target_bitrate); + const std::vector<rtcp::TargetBitrate::BitrateItem>& bitrates = + target_bitrate->GetTargetBitrates(); + EXPECT_EQ(kNumSpatialLayers * kNumTemporalLayers, bitrates.size()); + + for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) { + uint32_t start_bitrate_bps = (sl + 1) * 100000; + for (size_t tl = 0; tl < kNumTemporalLayers; ++tl) { + size_t index = (sl * kNumSpatialLayers) + tl; + const rtcp::TargetBitrate::BitrateItem& item = bitrates[index]; + EXPECT_EQ(sl, item.spatial_layer); + EXPECT_EQ(tl, item.temporal_layer); + EXPECT_EQ(start_bitrate_bps + (tl * 20000), + item.target_bitrate_kbps * 1000); + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.cc new file mode 100644 index 0000000000..c0b829c53e --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.cc @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtcp_transceiver.h" + +#include <utility> + +#include "rtc_base/checks.h" +#include "rtc_base/event.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/timeutils.h" + +namespace webrtc { + +RtcpTransceiver::RtcpTransceiver(const RtcpTransceiverConfig& config) + : task_queue_(config.task_queue), + rtcp_transceiver_(rtc::MakeUnique<RtcpTransceiverImpl>(config)), + ptr_factory_(rtcp_transceiver_.get()), + // Creating first weak ptr can be done on any thread, but is not + // thread-safe, thus do it at construction. Creating second (e.g. making a + // copy) is thread-safe. + ptr_(ptr_factory_.GetWeakPtr()) { + RTC_DCHECK(task_queue_); +} + +RtcpTransceiver::~RtcpTransceiver() { + if (task_queue_->IsCurrent()) + return; + + rtc::Event done(false, false); + // TODO(danilchap): Merge cleanup into main closure when task queue does not + // silently drop tasks. + task_queue_->PostTask(rtc::NewClosure( + [this] { + // Destructor steps that has to run on the task_queue_. + ptr_factory_.InvalidateWeakPtrs(); + rtcp_transceiver_.reset(); + }, + /*cleanup=*/[&done] { done.Set(); })); + // Wait until destruction is complete to be sure weak pointers invalidated and + // rtcp_transceiver destroyed on the queue while |this| still valid. + done.Wait(rtc::Event::kForever); + RTC_CHECK(!rtcp_transceiver_) << "Task queue is too busy to handle rtcp"; +} + +void RtcpTransceiver::ReceivePacket(rtc::CopyOnWriteBuffer packet) { + rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_; + int64_t now_us = rtc::TimeMicros(); + task_queue_->PostTask([ptr, packet, now_us] { + if (ptr) + ptr->ReceivePacket(packet, now_us); + }); +} + +void RtcpTransceiver::SendCompoundPacket() { + rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_; + task_queue_->PostTask([ptr] { + if (ptr) + ptr->SendCompoundPacket(); + }); +} + +void RtcpTransceiver::SetRemb(int bitrate_bps, std::vector<uint32_t> ssrcs) { + // TODO(danilchap): Replace with lambda with move capture when available. + struct SetRembClosure { + void operator()() { + if (ptr) + ptr->SetRemb(bitrate_bps, std::move(ssrcs)); + } + + rtc::WeakPtr<RtcpTransceiverImpl> ptr; + int bitrate_bps; + std::vector<uint32_t> ssrcs; + }; + task_queue_->PostTask(SetRembClosure{ptr_, bitrate_bps, std::move(ssrcs)}); +} + +void RtcpTransceiver::UnsetRemb() { + rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_; + task_queue_->PostTask([ptr] { + if (ptr) + ptr->UnsetRemb(); + }); +} + +void RtcpTransceiver::SendNack(uint32_t ssrc, + std::vector<uint16_t> sequence_numbers) { + // TODO(danilchap): Replace with lambda with move capture when available. + struct Closure { + void operator()() { + if (ptr) + ptr->SendNack(ssrc, std::move(sequence_numbers)); + } + + rtc::WeakPtr<RtcpTransceiverImpl> ptr; + uint32_t ssrc; + std::vector<uint16_t> sequence_numbers; + }; + task_queue_->PostTask(Closure{ptr_, ssrc, std::move(sequence_numbers)}); +} + +void RtcpTransceiver::SendPictureLossIndication(std::vector<uint32_t> ssrcs) { + // TODO(danilchap): Replace with lambda with move capture when available. + struct Closure { + void operator()() { + if (ptr) + ptr->SendPictureLossIndication(ssrcs); + } + + rtc::WeakPtr<RtcpTransceiverImpl> ptr; + std::vector<uint32_t> ssrcs; + }; + task_queue_->PostTask(Closure{ptr_, std::move(ssrcs)}); +} + +void RtcpTransceiver::SendFullIntraRequest(std::vector<uint32_t> ssrcs) { + // TODO(danilchap): Replace with lambda with move capture when available. + struct Closure { + void operator()() { + if (ptr) + ptr->SendFullIntraRequest(ssrcs); + } + + rtc::WeakPtr<RtcpTransceiverImpl> ptr; + std::vector<uint32_t> ssrcs; + }; + task_queue_->PostTask(Closure{ptr_, std::move(ssrcs)}); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.h new file mode 100644 index 0000000000..417943a164 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017 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_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h" +#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/copyonwritebuffer.h" +#include "rtc_base/task_queue.h" +#include "rtc_base/weak_ptr.h" + +namespace webrtc { +// +// Manage incoming and outgoing rtcp messages for multiple BUNDLED streams. +// +// This class is thread-safe wrapper of RtcpTransceiverImpl +class RtcpTransceiver { + public: + explicit RtcpTransceiver(const RtcpTransceiverConfig& config); + ~RtcpTransceiver(); + + // Handles incoming rtcp packets. + void ReceivePacket(rtc::CopyOnWriteBuffer packet); + + // Sends RTCP packets starting with a sender or receiver report. + void SendCompoundPacket(); + + // (REMB) Receiver Estimated Max Bitrate. + // Includes REMB in following compound packets. + void SetRemb(int bitrate_bps, std::vector<uint32_t> ssrcs); + // Stops sending REMB in following compound packets. + void UnsetRemb(); + + // Reports missing packets, https://tools.ietf.org/html/rfc4585#section-6.2.1 + void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers); + + // Requests new key frame. + // using PLI, https://tools.ietf.org/html/rfc4585#section-6.3.1.1 + void SendPictureLossIndication(std::vector<uint32_t> ssrcs); + // using FIR, https://tools.ietf.org/html/rfc5104#section-4.3.1.2 + void SendFullIntraRequest(std::vector<uint32_t> ssrcs); + + private: + rtc::TaskQueue* const task_queue_; + std::unique_ptr<RtcpTransceiverImpl> rtcp_transceiver_; + rtc::WeakPtrFactory<RtcpTransceiverImpl> ptr_factory_; + // TaskQueue, and thus tasks posted to it, may outlive this. + // Thus when Posting task class always pass copy of the weak_ptr to access + // the RtcpTransceiver and never guarantee it still will be alive when task + // runs. + rtc::WeakPtr<RtcpTransceiverImpl> ptr_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtcpTransceiver); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.cc new file mode 100644 index 0000000000..d6313ae1cd --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtcp_transceiver_config.h" + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +RtcpTransceiverConfig::RtcpTransceiverConfig() = default; +RtcpTransceiverConfig::RtcpTransceiverConfig(const RtcpTransceiverConfig&) = + default; +RtcpTransceiverConfig& RtcpTransceiverConfig::operator=( + const RtcpTransceiverConfig&) = default; +RtcpTransceiverConfig::~RtcpTransceiverConfig() = default; + +bool RtcpTransceiverConfig::Validate() const { + if (feedback_ssrc == 0) + RTC_LOG(LS_WARNING) + << debug_id + << "Ssrc 0 may be treated by some implementation as invalid."; + if (cname.empty()) + RTC_LOG(LS_WARNING) << debug_id << "missing cname for ssrc " + << feedback_ssrc; + if (cname.size() > 255) { + RTC_LOG(LS_ERROR) << debug_id << "cname can be maximum 255 characters."; + return false; + } + if (max_packet_size < 100) { + RTC_LOG(LS_ERROR) << debug_id << "max packet size " << max_packet_size + << " is too small."; + return false; + } + if (max_packet_size > IP_PACKET_SIZE) { + RTC_LOG(LS_ERROR) << debug_id << "max packet size " << max_packet_size + << " more than " << IP_PACKET_SIZE << " is unsupported."; + return false; + } + if (!outgoing_transport) { + RTC_LOG(LS_ERROR) << debug_id << "outgoing transport must be set"; + return false; + } + if (initial_report_delay_ms < 0) { + RTC_LOG(LS_ERROR) << debug_id << "delay " << initial_report_delay_ms + << "ms before first report shouldn't be negative."; + return false; + } + if (report_period_ms <= 0) { + RTC_LOG(LS_ERROR) << debug_id << "period " << report_period_ms + << "ms between reports should be positive."; + return false; + } + if (schedule_periodic_compound_packets && !task_queue) { + RTC_LOG(LS_ERROR) << debug_id + << "missing task queue for periodic compound packets"; + return false; + } + if (rtcp_mode != RtcpMode::kCompound && rtcp_mode != RtcpMode::kReducedSize) { + RTC_LOG(LS_ERROR) << debug_id << "unsupported rtcp mode"; + return false; + } + // TODO(danilchap): Remove or update the warning when RtcpTransceiver supports + // send-only sessions. + if (receive_statistics == nullptr) + RTC_LOG(LS_WARNING) + << debug_id + << "receive statistic should be set to generate rtcp report blocks."; + return true; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.h new file mode 100644 index 0000000000..07f4c51523 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 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_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_ + +#include <string> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/task_queue.h" + +namespace webrtc { +class ReceiveStatisticsProvider; +class Transport; + +struct RtcpTransceiverConfig { + RtcpTransceiverConfig(); + RtcpTransceiverConfig(const RtcpTransceiverConfig&); + RtcpTransceiverConfig& operator=(const RtcpTransceiverConfig&); + ~RtcpTransceiverConfig(); + + // Logs the error and returns false if configuration miss key objects or + // is inconsistant. May log warnings. + bool Validate() const; + + // Used to prepend all log messages. Can be empty. + std::string debug_id; + + // Ssrc to use as default sender ssrc, e.g. for transport-wide feedbacks. + uint32_t feedback_ssrc = 1; + + // Canonical End-Point Identifier of the local particiapnt. + // Defined in rfc3550 section 6 note 2 and section 6.5.1. + std::string cname; + + // Maximum packet size outgoing transport accepts. + size_t max_packet_size = 1200; + + // Transport to send rtcp packets to. Should be set. + Transport* outgoing_transport = nullptr; + + // Queue for scheduling delayed tasks, e.g. sending periodic compound packets. + rtc::TaskQueue* task_queue = nullptr; + + // Rtcp report block generator for outgoing receiver reports. + ReceiveStatisticsProvider* receive_statistics = nullptr; + + // Configures if sending should + // enforce compound packets: https://tools.ietf.org/html/rfc4585#section-3.1 + // or allow reduced size packets: https://tools.ietf.org/html/rfc5506 + // Receiving accepts both compound and reduced-size packets. + RtcpMode rtcp_mode = RtcpMode::kCompound; + // + // Tuning parameters. + // + // Delay before 1st periodic compound packet. + int initial_report_delay_ms = 500; + + // Period between periodic compound packets. + int report_period_ms = 1000; + + // + // Flags for features and experiments. + // + bool schedule_periodic_compound_packets = true; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc new file mode 100644 index 0000000000..fbe1717c2a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtcp_transceiver_impl.h" + +#include <utility> + +#include "api/call/transport.h" +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtcp_packet/pli.h" +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h" +#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/ptr_util.h" +#include "rtc_base/task_queue.h" +#include "rtc_base/timeutils.h" + +namespace webrtc { +namespace { + +struct SenderReportTimes { + int64_t local_received_time_us; + NtpTime remote_sent_time; +}; + +} // namespace + +struct RtcpTransceiverImpl::RemoteSenderState { + uint8_t fir_sequence_number = 0; + rtc::Optional<SenderReportTimes> last_received_sender_report; +}; + +// Helper to put several RTCP packets into lower layer datagram composing +// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2. +// TODO(danilchap): When in compound mode and packets are so many that several +// compound RTCP packets need to be generated, ensure each packet is compound. +class RtcpTransceiverImpl::PacketSender + : public rtcp::RtcpPacket::PacketReadyCallback { + public: + PacketSender(Transport* transport, size_t max_packet_size) + : transport_(transport), max_packet_size_(max_packet_size) { + RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE); + } + ~PacketSender() override { + RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet."; + } + + // Appends a packet to pending compound packet. + // Sends rtcp compound packet if buffer was already full and resets buffer. + void AppendPacket(const rtcp::RtcpPacket& packet) { + packet.Create(buffer_, &index_, max_packet_size_, this); + } + + // Sends pending rtcp compound packet. + void Send() { + if (index_ > 0) { + OnPacketReady(buffer_, index_); + index_ = 0; + } + } + + bool IsEmpty() const { return index_ == 0; } + + private: + // Implements RtcpPacket::PacketReadyCallback + void OnPacketReady(uint8_t* data, size_t length) override { + transport_->SendRtcp(data, length); + } + + Transport* const transport_; + const size_t max_packet_size_; + size_t index_ = 0; + uint8_t buffer_[IP_PACKET_SIZE]; +}; + +RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config) + : config_(config), ptr_factory_(this) { + RTC_CHECK(config_.Validate()); + if (config_.schedule_periodic_compound_packets) + SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms); +} + +RtcpTransceiverImpl::~RtcpTransceiverImpl() = default; + +void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet, + int64_t now_us) { + while (!packet.empty()) { + rtcp::CommonHeader rtcp_block; + if (!rtcp_block.Parse(packet.data(), packet.size())) + return; + + HandleReceivedPacket(rtcp_block, now_us); + + // TODO(danilchap): Use packet.remove_prefix() when that function exists. + packet = packet.subview(rtcp_block.packet_size()); + } +} + +void RtcpTransceiverImpl::SendCompoundPacket() { + SendPeriodicCompoundPacket(); + ReschedulePeriodicCompoundPackets(); +} + +void RtcpTransceiverImpl::SetRemb(int bitrate_bps, + std::vector<uint32_t> ssrcs) { + RTC_DCHECK_GE(bitrate_bps, 0); + remb_.emplace(); + remb_->SetSsrcs(std::move(ssrcs)); + remb_->SetBitrateBps(bitrate_bps); + // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb + // immideately on large bitrate change when there is one RtcpTransceiver per + // rtp transport. +} + +void RtcpTransceiverImpl::UnsetRemb() { + remb_.reset(); +} + +void RtcpTransceiverImpl::SendNack(uint32_t ssrc, + std::vector<uint16_t> sequence_numbers) { + RTC_DCHECK(!sequence_numbers.empty()); + SendImmediateFeedback([&](PacketSender* sender) { + rtcp::Nack nack; + nack.SetSenderSsrc(config_.feedback_ssrc); + nack.SetMediaSsrc(ssrc); + nack.SetPacketIds(std::move(sequence_numbers)); + sender->AppendPacket(nack); + }); +} + +void RtcpTransceiverImpl::SendPictureLossIndication( + rtc::ArrayView<const uint32_t> ssrcs) { + RTC_DCHECK(!ssrcs.empty()); + SendImmediateFeedback([this, ssrcs](PacketSender* sender) { + for (uint32_t media_ssrc : ssrcs) { + rtcp::Pli pli; + pli.SetSenderSsrc(config_.feedback_ssrc); + pli.SetMediaSsrc(media_ssrc); + sender->AppendPacket(pli); + } + }); +} + +void RtcpTransceiverImpl::SendFullIntraRequest( + rtc::ArrayView<const uint32_t> ssrcs) { + RTC_DCHECK(!ssrcs.empty()); + SendImmediateFeedback([this, ssrcs](PacketSender* sender) { + rtcp::Fir fir; + fir.SetSenderSsrc(config_.feedback_ssrc); + for (uint32_t media_ssrc : ssrcs) + fir.AddRequestTo(media_ssrc, + remote_senders_[media_ssrc].fir_sequence_number++); + sender->AppendPacket(fir); + }); +} + +void RtcpTransceiverImpl::HandleReceivedPacket( + const rtcp::CommonHeader& rtcp_packet_header, + int64_t now_us) { + switch (rtcp_packet_header.type()) { + case rtcp::SenderReport::kPacketType: { + rtcp::SenderReport sender_report; + if (!sender_report.Parse(rtcp_packet_header)) + return; + rtc::Optional<SenderReportTimes>& last = + remote_senders_[sender_report.sender_ssrc()] + .last_received_sender_report; + last.emplace(); + last->local_received_time_us = now_us; + last->remote_sent_time = sender_report.ntp(); + break; + } + } +} + +void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() { + if (!config_.schedule_periodic_compound_packets) + return; + // Stop existent send task. + ptr_factory_.InvalidateWeakPtrs(); + SchedulePeriodicCompoundPackets(config_.report_period_ms); +} + +void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) { + class SendPeriodicCompoundPacketTask : public rtc::QueuedTask { + public: + SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue, + rtc::WeakPtr<RtcpTransceiverImpl> ptr) + : task_queue_(task_queue), ptr_(std::move(ptr)) {} + bool Run() override { + RTC_DCHECK(task_queue_->IsCurrent()); + if (!ptr_) + return true; + ptr_->SendPeriodicCompoundPacket(); + task_queue_->PostDelayedTask(rtc::WrapUnique(this), + ptr_->config_.report_period_ms); + return false; + } + + private: + rtc::TaskQueue* const task_queue_; + const rtc::WeakPtr<RtcpTransceiverImpl> ptr_; + }; + + RTC_DCHECK(config_.schedule_periodic_compound_packets); + + auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>( + config_.task_queue, ptr_factory_.GetWeakPtr()); + if (delay_ms > 0) + config_.task_queue->PostDelayedTask(std::move(task), delay_ms); + else + config_.task_queue->PostTask(std::move(task)); +} + +void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) { + RTC_DCHECK(sender->IsEmpty()); + const uint32_t sender_ssrc = config_.feedback_ssrc; + rtcp::ReceiverReport receiver_report; + receiver_report.SetSenderSsrc(sender_ssrc); + receiver_report.SetReportBlocks(CreateReportBlocks()); + sender->AppendPacket(receiver_report); + + if (!config_.cname.empty()) { + rtcp::Sdes sdes; + bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname); + RTC_DCHECK(added) << "Failed to add cname " << config_.cname + << " to rtcp sdes packet."; + sender->AppendPacket(sdes); + } + if (remb_) { + remb_->SetSenderSsrc(sender_ssrc); + sender->AppendPacket(*remb_); + } +} + +void RtcpTransceiverImpl::SendPeriodicCompoundPacket() { + PacketSender sender(config_.outgoing_transport, config_.max_packet_size); + CreateCompoundPacket(&sender); + sender.Send(); +} + +void RtcpTransceiverImpl::SendImmediateFeedback( + rtc::FunctionView<void(PacketSender*)> append_feedback) { + PacketSender sender(config_.outgoing_transport, config_.max_packet_size); + if (config_.rtcp_mode == RtcpMode::kCompound) + CreateCompoundPacket(&sender); + + append_feedback(&sender); + + sender.Send(); + + if (config_.rtcp_mode == RtcpMode::kCompound) + ReschedulePeriodicCompoundPackets(); +} + +std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks() { + if (!config_.receive_statistics) + return {}; + // TODO(danilchap): Support sending more than + // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet. + std::vector<rtcp::ReportBlock> report_blocks = + config_.receive_statistics->RtcpReportBlocks( + rtcp::ReceiverReport::kMaxNumberOfReportBlocks); + for (rtcp::ReportBlock& report_block : report_blocks) { + auto it = remote_senders_.find(report_block.source_ssrc()); + if (it == remote_senders_.end() || !it->second.last_received_sender_report) + continue; + const SenderReportTimes& last_sender_report = + *it->second.last_received_sender_report; + report_block.SetLastSr(CompactNtp(last_sender_report.remote_sent_time)); + report_block.SetDelayLastSr(SaturatedUsToCompactNtp( + rtc::TimeMicros() - last_sender_report.local_received_time_us)); + } + return report_blocks; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.h new file mode 100644 index 0000000000..8cde921213 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017 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_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_ + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "api/array_view.h" +#include "api/optional.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "modules/rtp_rtcp/source/rtcp_packet/remb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" +#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/function_view.h" +#include "rtc_base/weak_ptr.h" +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { +// +// Manage incoming and outgoing rtcp messages for multiple BUNDLED streams. +// +// This class is not thread-safe. +class RtcpTransceiverImpl { + public: + explicit RtcpTransceiverImpl(const RtcpTransceiverConfig& config); + ~RtcpTransceiverImpl(); + + void ReceivePacket(rtc::ArrayView<const uint8_t> packet, int64_t now_us); + + void SendCompoundPacket(); + + void SetRemb(int bitrate_bps, std::vector<uint32_t> ssrcs); + void UnsetRemb(); + + void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers); + + void SendPictureLossIndication(rtc::ArrayView<const uint32_t> ssrcs); + void SendFullIntraRequest(rtc::ArrayView<const uint32_t> ssrcs); + + private: + class PacketSender; + struct RemoteSenderState; + + void HandleReceivedPacket(const rtcp::CommonHeader& rtcp_packet_header, + int64_t now_us); + + void ReschedulePeriodicCompoundPackets(); + void SchedulePeriodicCompoundPackets(int64_t delay_ms); + // Creates compound RTCP packet, as defined in + // https://tools.ietf.org/html/rfc5506#section-2 + void CreateCompoundPacket(PacketSender* sender); + // Sends RTCP packets. + void SendPeriodicCompoundPacket(); + void SendImmediateFeedback( + rtc::FunctionView<void(PacketSender*)> append_feedback); + // Generate Report Blocks to be send in Sender or Receiver Report. + std::vector<rtcp::ReportBlock> CreateReportBlocks(); + + const RtcpTransceiverConfig config_; + + rtc::Optional<rtcp::Remb> remb_; + std::map<uint32_t, RemoteSenderState> remote_senders_; + rtc::WeakPtrFactory<RtcpTransceiverImpl> ptr_factory_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtcpTransceiverImpl); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc new file mode 100644 index 0000000000..9690506854 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtcp_transceiver_impl.h" + +#include <vector> + +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "modules/rtp_rtcp/source/time_util.h" +#include "rtc_base/event.h" +#include "rtc_base/fakeclock.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/task_queue.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/mock_transport.h" +#include "test/rtcp_packet_parser.h" + +namespace { + +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SizeIs; +using ::webrtc::CompactNtp; +using ::webrtc::CompactNtpRttToMs; +using ::webrtc::MockTransport; +using ::webrtc::NtpTime; +using ::webrtc::RtcpTransceiverConfig; +using ::webrtc::RtcpTransceiverImpl; +using ::webrtc::rtcp::ReportBlock; +using ::webrtc::rtcp::SenderReport; +using ::webrtc::test::RtcpPacketParser; + +class MockReceiveStatisticsProvider : public webrtc::ReceiveStatisticsProvider { + public: + MOCK_METHOD1(RtcpReportBlocks, std::vector<ReportBlock>(size_t)); +}; + +// Since some tests will need to wait for this period, make it small to avoid +// slowing tests too much. As long as there are test bots with high scheduler +// granularity, small period should be ok. +constexpr int kReportPeriodMs = 10; +// On some systems task queue might be slow, instead of guessing right +// grace period, use very large timeout, 100x larger expected wait time. +// Use finite timeout to fail tests rather than hang them. +constexpr int kAlmostForeverMs = 1000; + +// Helper to wait for an rtcp packet produced on a different thread/task queue. +class FakeRtcpTransport : public webrtc::Transport { + public: + FakeRtcpTransport() : sent_rtcp_(false, false) {} + bool SendRtcp(const uint8_t* data, size_t size) override { + sent_rtcp_.Set(); + return true; + } + bool SendRtp(const uint8_t*, size_t, const webrtc::PacketOptions&) override { + ADD_FAILURE() << "RtcpTransciver shouldn't send rtp packets."; + return true; + } + + // Returns true when packet was received by the transport. + bool WaitPacket() { + // Normally packet should be sent fast, long before the timeout. + bool packet_sent = sent_rtcp_.Wait(kAlmostForeverMs); + // Disallow tests to wait almost forever for no packets. + EXPECT_TRUE(packet_sent); + // Return wait result even though it is expected to be true, so that + // individual tests can EXPECT on it for better error message. + return packet_sent; + } + + private: + rtc::Event sent_rtcp_; +}; + +class RtcpParserTransport : public webrtc::Transport { + public: + explicit RtcpParserTransport(RtcpPacketParser* parser) : parser_(parser) {} + // Returns total number of rtcp packet received. + int num_packets() const { return num_packets_; } + + private: + bool SendRtcp(const uint8_t* data, size_t size) override { + ++num_packets_; + parser_->Parse(data, size); + return true; + } + + bool SendRtp(const uint8_t*, size_t, const webrtc::PacketOptions&) override { + ADD_FAILURE() << "RtcpTransciver shouldn't send rtp packets."; + return true; + } + + RtcpPacketParser* const parser_; + int num_packets_ = 0; +}; + +TEST(RtcpTransceiverImplTest, DelaysSendingFirstCompondPacket) { + rtc::TaskQueue queue("rtcp"); + FakeRtcpTransport transport; + RtcpTransceiverConfig config; + config.outgoing_transport = &transport; + config.initial_report_delay_ms = 10; + config.task_queue = &queue; + rtc::Optional<RtcpTransceiverImpl> rtcp_transceiver; + + int64_t started_ms = rtc::TimeMillis(); + queue.PostTask([&] { rtcp_transceiver.emplace(config); }); + EXPECT_TRUE(transport.WaitPacket()); + + EXPECT_GE(rtc::TimeMillis() - started_ms, config.initial_report_delay_ms); + + // Cleanup. + rtc::Event done(false, false); + queue.PostTask([&] { + rtcp_transceiver.reset(); + done.Set(); + }); + ASSERT_TRUE(done.Wait(kAlmostForeverMs)); +} + +TEST(RtcpTransceiverImplTest, PeriodicallySendsPackets) { + rtc::TaskQueue queue("rtcp"); + FakeRtcpTransport transport; + RtcpTransceiverConfig config; + config.outgoing_transport = &transport; + config.initial_report_delay_ms = 0; + config.report_period_ms = kReportPeriodMs; + config.task_queue = &queue; + rtc::Optional<RtcpTransceiverImpl> rtcp_transceiver; + int64_t time_just_before_1st_packet_ms = 0; + queue.PostTask([&] { + // Because initial_report_delay_ms is set to 0, time_just_before_the_packet + // should be very close to the time_of_the_packet. + time_just_before_1st_packet_ms = rtc::TimeMillis(); + rtcp_transceiver.emplace(config); + }); + + EXPECT_TRUE(transport.WaitPacket()); + EXPECT_TRUE(transport.WaitPacket()); + int64_t time_just_after_2nd_packet_ms = rtc::TimeMillis(); + + EXPECT_GE(time_just_after_2nd_packet_ms - time_just_before_1st_packet_ms, + config.report_period_ms); + + // Cleanup. + rtc::Event done(false, false); + queue.PostTask([&] { + rtcp_transceiver.reset(); + done.Set(); + }); + ASSERT_TRUE(done.Wait(kAlmostForeverMs)); +} + +TEST(RtcpTransceiverImplTest, SendCompoundPacketDelaysPeriodicSendPackets) { + rtc::TaskQueue queue("rtcp"); + FakeRtcpTransport transport; + RtcpTransceiverConfig config; + config.outgoing_transport = &transport; + config.initial_report_delay_ms = 0; + config.report_period_ms = kReportPeriodMs; + config.task_queue = &queue; + rtc::Optional<RtcpTransceiverImpl> rtcp_transceiver; + queue.PostTask([&] { rtcp_transceiver.emplace(config); }); + + // Wait for first packet. + EXPECT_TRUE(transport.WaitPacket()); + // Send non periodic one after half period. + rtc::Event non_periodic(false, false); + int64_t time_of_non_periodic_packet_ms = 0; + queue.PostDelayedTask( + [&] { + time_of_non_periodic_packet_ms = rtc::TimeMillis(); + rtcp_transceiver->SendCompoundPacket(); + non_periodic.Set(); + }, + config.report_period_ms / 2); + // Though non-periodic packet is scheduled just in between periodic, due to + // small period and task queue flakiness it migth end-up 1ms after next + // periodic packet. To be sure duration after non-periodic packet is tested + // wait for transport after ensuring non-periodic packet was sent. + EXPECT_TRUE(non_periodic.Wait(kAlmostForeverMs)); + EXPECT_TRUE(transport.WaitPacket()); + // Wait for next periodic packet. + EXPECT_TRUE(transport.WaitPacket()); + int64_t time_of_last_periodic_packet_ms = rtc::TimeMillis(); + + EXPECT_GE(time_of_last_periodic_packet_ms - time_of_non_periodic_packet_ms, + config.report_period_ms); + + // Cleanup. + rtc::Event done(false, false); + queue.PostTask([&] { + rtcp_transceiver.reset(); + done.Set(); + }); + ASSERT_TRUE(done.Wait(kAlmostForeverMs)); +} + +TEST(RtcpTransceiverImplTest, SendsMinimalCompoundPacket) { + const uint32_t kSenderSsrc = 12345; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + config.cname = "cname"; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.schedule_periodic_compound_packets = false; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SendCompoundPacket(); + + // Minimal compound RTCP packet contains sender or receiver report and sdes + // with cname. + ASSERT_GT(rtcp_parser.receiver_report()->num_packets(), 0); + EXPECT_EQ(rtcp_parser.receiver_report()->sender_ssrc(), kSenderSsrc); + ASSERT_GT(rtcp_parser.sdes()->num_packets(), 0); + ASSERT_EQ(rtcp_parser.sdes()->chunks().size(), 1u); + EXPECT_EQ(rtcp_parser.sdes()->chunks()[0].ssrc, kSenderSsrc); + EXPECT_EQ(rtcp_parser.sdes()->chunks()[0].cname, config.cname); +} + +TEST(RtcpTransceiverImplTest, SendsNoRembInitially) { + const uint32_t kSenderSsrc = 12345; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.schedule_periodic_compound_packets = false; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(transport.num_packets(), 1); + EXPECT_EQ(rtcp_parser.remb()->num_packets(), 0); +} + +TEST(RtcpTransceiverImplTest, SetRembIncludesRembInNextCompoundPacket) { + const uint32_t kSenderSsrc = 12345; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.schedule_periodic_compound_packets = false; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321}); + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1); + EXPECT_EQ(rtcp_parser.remb()->sender_ssrc(), kSenderSsrc); + EXPECT_EQ(rtcp_parser.remb()->bitrate_bps(), 10000u); + EXPECT_THAT(rtcp_parser.remb()->ssrcs(), ElementsAre(54321, 64321)); +} + +TEST(RtcpTransceiverImplTest, SetRembUpdatesValuesToSend) { + const uint32_t kSenderSsrc = 12345; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.schedule_periodic_compound_packets = false; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321}); + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1); + EXPECT_EQ(rtcp_parser.remb()->bitrate_bps(), 10000u); + EXPECT_THAT(rtcp_parser.remb()->ssrcs(), ElementsAre(54321, 64321)); + + rtcp_transceiver.SetRemb(/*bitrate_bps=*/70000, /*ssrc=*/{67321}); + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(rtcp_parser.remb()->num_packets(), 2); + EXPECT_EQ(rtcp_parser.remb()->bitrate_bps(), 70000u); + EXPECT_THAT(rtcp_parser.remb()->ssrcs(), ElementsAre(67321)); +} + +TEST(RtcpTransceiverImplTest, SetRembIncludesRembInAllCompoundPackets) { + const uint32_t kSenderSsrc = 12345; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.schedule_periodic_compound_packets = false; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321}); + rtcp_transceiver.SendCompoundPacket(); + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(transport.num_packets(), 2); + EXPECT_EQ(rtcp_parser.remb()->num_packets(), 2); +} + +TEST(RtcpTransceiverImplTest, SendsNoRembAfterUnset) { + const uint32_t kSenderSsrc = 12345; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.schedule_periodic_compound_packets = false; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321}); + rtcp_transceiver.SendCompoundPacket(); + EXPECT_EQ(transport.num_packets(), 1); + ASSERT_EQ(rtcp_parser.remb()->num_packets(), 1); + + rtcp_transceiver.UnsetRemb(); + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_EQ(transport.num_packets(), 2); + EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1); +} + +TEST(RtcpTransceiverImplTest, ReceiverReportUsesReceiveStatistics) { + const uint32_t kSenderSsrc = 12345; + const uint32_t kMediaSsrc = 54321; + MockReceiveStatisticsProvider receive_statistics; + std::vector<ReportBlock> report_blocks(1); + report_blocks[0].SetMediaSsrc(kMediaSsrc); + EXPECT_CALL(receive_statistics, RtcpReportBlocks(_)) + .WillRepeatedly(Return(report_blocks)); + + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.receive_statistics = &receive_statistics; + config.schedule_periodic_compound_packets = false; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SendCompoundPacket(); + + ASSERT_GT(rtcp_parser.receiver_report()->num_packets(), 0); + EXPECT_EQ(rtcp_parser.receiver_report()->sender_ssrc(), kSenderSsrc); + ASSERT_THAT(rtcp_parser.receiver_report()->report_blocks(), + SizeIs(report_blocks.size())); + EXPECT_EQ(rtcp_parser.receiver_report()->report_blocks()[0].source_ssrc(), + kMediaSsrc); +} + +// TODO(danilchap): Write test ReceivePacket handles several rtcp_packets +// stacked together when callbacks will be implemented that can be used for +// cleaner expectations. + +TEST(RtcpTransceiverImplTest, + WhenSendsReceiverReportSetsLastSenderReportTimestampPerRemoteSsrc) { + const uint32_t kRemoteSsrc1 = 4321; + const uint32_t kRemoteSsrc2 = 5321; + std::vector<ReportBlock> statistics_report_blocks(2); + statistics_report_blocks[0].SetMediaSsrc(kRemoteSsrc1); + statistics_report_blocks[1].SetMediaSsrc(kRemoteSsrc2); + MockReceiveStatisticsProvider receive_statistics; + EXPECT_CALL(receive_statistics, RtcpReportBlocks(_)) + .WillOnce(Return(statistics_report_blocks)); + + RtcpTransceiverConfig config; + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.receive_statistics = &receive_statistics; + RtcpTransceiverImpl rtcp_transceiver(config); + + const NtpTime kRemoteNtp(0x9876543211); + // Receive SenderReport for RemoteSsrc2, but no report for RemoteSsrc1. + SenderReport sr; + sr.SetSenderSsrc(kRemoteSsrc2); + sr.SetNtp(kRemoteNtp); + auto raw_packet = sr.Build(); + rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0); + + // Trigger sending ReceiverReport. + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_GT(rtcp_parser.receiver_report()->num_packets(), 0); + const auto& report_blocks = rtcp_parser.receiver_report()->report_blocks(); + ASSERT_EQ(report_blocks.size(), 2u); + // RtcpTransceiverImpl doesn't guarantee order of the report blocks + // 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); + // No matching Sender Report for kRemoteSsrc1, LastSR fields has to be 0. + EXPECT_EQ(report_blocks[0].last_sr(), 0u); + + ASSERT_EQ(report_blocks[1].source_ssrc(), kRemoteSsrc2); + EXPECT_EQ(report_blocks[1].last_sr(), CompactNtp(kRemoteNtp)); +} + +TEST(RtcpTransceiverImplTest, + WhenSendsReceiverReportCalculatesDelaySinceLastSenderReport) { + const uint32_t kRemoteSsrc1 = 4321; + const uint32_t kRemoteSsrc2 = 5321; + rtc::ScopedFakeClock clock; + std::vector<ReportBlock> statistics_report_blocks(2); + statistics_report_blocks[0].SetMediaSsrc(kRemoteSsrc1); + statistics_report_blocks[1].SetMediaSsrc(kRemoteSsrc2); + MockReceiveStatisticsProvider receive_statistics; + EXPECT_CALL(receive_statistics, RtcpReportBlocks(_)) + .WillOnce(Return(statistics_report_blocks)); + + RtcpTransceiverConfig config; + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + config.receive_statistics = &receive_statistics; + RtcpTransceiverImpl rtcp_transceiver(config); + + auto receive_sender_report = [&rtcp_transceiver](uint32_t remote_ssrc) { + SenderReport sr; + sr.SetSenderSsrc(remote_ssrc); + auto raw_packet = sr.Build(); + rtcp_transceiver.ReceivePacket(raw_packet, rtc::TimeMicros()); + }; + + receive_sender_report(kRemoteSsrc1); + clock.AdvanceTimeMicros(100 * rtc::kNumMicrosecsPerMillisec); + + receive_sender_report(kRemoteSsrc2); + clock.AdvanceTimeMicros(100 * rtc::kNumMicrosecsPerMillisec); + + // Trigger ReceiverReport back. + rtcp_transceiver.SendCompoundPacket(); + + EXPECT_GT(rtcp_parser.receiver_report()->num_packets(), 0); + const auto& report_blocks = rtcp_parser.receiver_report()->report_blocks(); + ASSERT_EQ(report_blocks.size(), 2u); + // RtcpTransceiverImpl doesn't guarantee order of the report blocks + // 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); + + ASSERT_EQ(report_blocks[1].source_ssrc(), kRemoteSsrc2); + EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100); +} + +TEST(RtcpTransceiverImplTest, SendsNack) { + const uint32_t kSenderSsrc = 1234; + const uint32_t kRemoteSsrc = 4321; + std::vector<uint16_t> kMissingSequenceNumbers = {34, 37, 38}; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SendNack(kRemoteSsrc, kMissingSequenceNumbers); + + EXPECT_EQ(rtcp_parser.nack()->num_packets(), 1); + EXPECT_EQ(rtcp_parser.nack()->sender_ssrc(), kSenderSsrc); + EXPECT_EQ(rtcp_parser.nack()->media_ssrc(), kRemoteSsrc); + EXPECT_EQ(rtcp_parser.nack()->packet_ids(), kMissingSequenceNumbers); +} + +TEST(RtcpTransceiverImplTest, RequestKeyFrameWithPictureLossIndication) { + const uint32_t kSenderSsrc = 1234; + const uint32_t kRemoteSsrcs[] = {4321, 5321}; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SendPictureLossIndication(kRemoteSsrcs); + + // Expect a pli packet per ssrc in the sent single compound packet. + EXPECT_EQ(transport.num_packets(), 1); + EXPECT_EQ(rtcp_parser.pli()->num_packets(), 2); + EXPECT_EQ(rtcp_parser.pli()->sender_ssrc(), kSenderSsrc); + // test::RtcpPacketParser overwrites first pli packet with second one. + EXPECT_EQ(rtcp_parser.pli()->media_ssrc(), kRemoteSsrcs[1]); +} + +TEST(RtcpTransceiverImplTest, RequestKeyFrameWithFullIntraRequest) { + const uint32_t kSenderSsrc = 1234; + const uint32_t kRemoteSsrcs[] = {4321, 5321}; + RtcpTransceiverConfig config; + config.feedback_ssrc = kSenderSsrc; + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SendFullIntraRequest(kRemoteSsrcs); + + EXPECT_EQ(rtcp_parser.fir()->num_packets(), 1); + EXPECT_EQ(rtcp_parser.fir()->sender_ssrc(), kSenderSsrc); + EXPECT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kRemoteSsrcs[0]); + EXPECT_EQ(rtcp_parser.fir()->requests()[1].ssrc, kRemoteSsrcs[1]); +} + +TEST(RtcpTransceiverImplTest, RequestKeyFrameWithFirIncreaseSeqNoPerSsrc) { + RtcpTransceiverConfig config; + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + const uint32_t kBothRemoteSsrcs[] = {4321, 5321}; + const uint32_t kOneRemoteSsrc[] = {4321}; + + rtcp_transceiver.SendFullIntraRequest(kBothRemoteSsrcs); + ASSERT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kBothRemoteSsrcs[0]); + uint8_t fir_sequence_number0 = rtcp_parser.fir()->requests()[0].seq_nr; + ASSERT_EQ(rtcp_parser.fir()->requests()[1].ssrc, kBothRemoteSsrcs[1]); + uint8_t fir_sequence_number1 = rtcp_parser.fir()->requests()[1].seq_nr; + + rtcp_transceiver.SendFullIntraRequest(kOneRemoteSsrc); + ASSERT_EQ(rtcp_parser.fir()->requests().size(), 1u); + ASSERT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kBothRemoteSsrcs[0]); + EXPECT_EQ(rtcp_parser.fir()->requests()[0].seq_nr, fir_sequence_number0 + 1); + + rtcp_transceiver.SendFullIntraRequest(kBothRemoteSsrcs); + ASSERT_EQ(rtcp_parser.fir()->requests().size(), 2u); + ASSERT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kBothRemoteSsrcs[0]); + EXPECT_EQ(rtcp_parser.fir()->requests()[0].seq_nr, fir_sequence_number0 + 2); + ASSERT_EQ(rtcp_parser.fir()->requests()[1].ssrc, kBothRemoteSsrcs[1]); + EXPECT_EQ(rtcp_parser.fir()->requests()[1].seq_nr, fir_sequence_number1 + 1); +} + +TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesCompoundPacket) { + const uint32_t kRemoteSsrcs[] = {4321}; + RtcpTransceiverConfig config; + // Turn periodic off to ensure sent rtcp packet is explicitly requested. + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + + config.rtcp_mode = webrtc::RtcpMode::kCompound; + + RtcpTransceiverImpl rtcp_transceiver(config); + rtcp_transceiver.SendFullIntraRequest(kRemoteSsrcs); + + // Test sent packet is compound by expecting presense of receiver report. + EXPECT_EQ(transport.num_packets(), 1); + EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 1); +} + +TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesReducedSizePacket) { + const uint32_t kRemoteSsrcs[] = {4321}; + RtcpTransceiverConfig config; + // Turn periodic off to ensure sent rtcp packet is explicitly requested. + config.schedule_periodic_compound_packets = false; + RtcpPacketParser rtcp_parser; + RtcpParserTransport transport(&rtcp_parser); + config.outgoing_transport = &transport; + + config.rtcp_mode = webrtc::RtcpMode::kReducedSize; + + RtcpTransceiverImpl rtcp_transceiver(config); + rtcp_transceiver.SendFullIntraRequest(kRemoteSsrcs); + + // Test sent packet is reduced size by expecting absense of receiver report. + EXPECT_EQ(transport.num_packets(), 1); + EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 0); +} + +} // namespace diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_unittest.cc new file mode 100644 index 0000000000..dea91dba86 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_unittest.cc @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtcp_transceiver.h" + +#include "rtc_base/event.h" +#include "rtc_base/ptr_util.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/mock_transport.h" + +namespace { + +using ::testing::AtLeast; +using ::testing::InvokeWithoutArgs; +using ::testing::NiceMock; +using ::testing::_; +using ::webrtc::MockTransport; +using ::webrtc::RtcpTransceiver; +using ::webrtc::RtcpTransceiverConfig; + +void WaitPostedTasks(rtc::TaskQueue* queue) { + rtc::Event done(false, false); + queue->PostTask([&done] { done.Set(); }); + ASSERT_TRUE(done.Wait(1000)); +} + +TEST(RtcpTransceiverTest, SendsRtcpOnTaskQueueWhenCreatedOffTaskQueue) { + rtc::TaskQueue queue("rtcp"); + MockTransport outgoing_transport; + RtcpTransceiverConfig config; + config.outgoing_transport = &outgoing_transport; + config.task_queue = &queue; + EXPECT_CALL(outgoing_transport, SendRtcp(_, _)) + .WillRepeatedly(InvokeWithoutArgs([&] { + EXPECT_TRUE(queue.IsCurrent()); + return true; + })); + + RtcpTransceiver rtcp_transceiver(config); + rtcp_transceiver.SendCompoundPacket(); + WaitPostedTasks(&queue); +} + +TEST(RtcpTransceiverTest, SendsRtcpOnTaskQueueWhenCreatedOnTaskQueue) { + rtc::TaskQueue queue("rtcp"); + MockTransport outgoing_transport; + RtcpTransceiverConfig config; + config.outgoing_transport = &outgoing_transport; + config.task_queue = &queue; + EXPECT_CALL(outgoing_transport, SendRtcp(_, _)) + .WillRepeatedly(InvokeWithoutArgs([&] { + EXPECT_TRUE(queue.IsCurrent()); + return true; + })); + + std::unique_ptr<RtcpTransceiver> rtcp_transceiver; + queue.PostTask([&] { + rtcp_transceiver = rtc::MakeUnique<RtcpTransceiver>(config); + rtcp_transceiver->SendCompoundPacket(); + }); + WaitPostedTasks(&queue); +} + +TEST(RtcpTransceiverTest, CanBeDestoryedOnTaskQueue) { + rtc::TaskQueue queue("rtcp"); + NiceMock<MockTransport> outgoing_transport; + RtcpTransceiverConfig config; + config.outgoing_transport = &outgoing_transport; + config.task_queue = &queue; + auto rtcp_transceiver = rtc::MakeUnique<RtcpTransceiver>(config); + + queue.PostTask([&] { rtcp_transceiver.reset(); }); + WaitPostedTasks(&queue); +} + +TEST(RtcpTransceiverTest, CanCallSendCompoundPacketFromAnyThread) { + MockTransport outgoing_transport; + rtc::TaskQueue queue("rtcp"); + RtcpTransceiverConfig config; + config.outgoing_transport = &outgoing_transport; + config.task_queue = &queue; + + EXPECT_CALL(outgoing_transport, SendRtcp(_, _)) + // If test is slow, a periodic task may send an extra packet. + .Times(AtLeast(3)) + .WillRepeatedly(InvokeWithoutArgs([&] { + EXPECT_TRUE(queue.IsCurrent()); + return true; + })); + + RtcpTransceiver rtcp_transceiver(config); + + // Call from the construction thread. + rtcp_transceiver.SendCompoundPacket(); + // Call from the same queue transceiver use for processing. + queue.PostTask([&] { rtcp_transceiver.SendCompoundPacket(); }); + // Call from unrelated task queue. + rtc::TaskQueue queue_send("send_packet"); + queue_send.PostTask([&] { rtcp_transceiver.SendCompoundPacket(); }); + + WaitPostedTasks(&queue_send); + WaitPostedTasks(&queue); +} + +TEST(RtcpTransceiverTest, DoesntSendPacketsAfterDestruction) { + MockTransport outgoing_transport; + rtc::TaskQueue queue("rtcp"); + RtcpTransceiverConfig config; + config.outgoing_transport = &outgoing_transport; + config.task_queue = &queue; + config.schedule_periodic_compound_packets = false; + + EXPECT_CALL(outgoing_transport, SendRtcp(_, _)).Times(0); + + auto rtcp_transceiver = rtc::MakeUnique<RtcpTransceiver>(config); + rtc::Event pause(false, false); + queue.PostTask([&] { + pause.Wait(rtc::Event::kForever); + rtcp_transceiver.reset(); + }); + rtcp_transceiver->SendCompoundPacket(); + pause.Set(); + WaitPostedTasks(&queue); + EXPECT_FALSE(rtcp_transceiver); +} + +} // namespace diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc new file mode 100644 index 0000000000..606dafbbf2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc @@ -0,0 +1,1116 @@ +/* + * 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 <algorithm> +#include <list> +#include <memory> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/fec_test_helper.h" +#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/random.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. +constexpr size_t kTransportOverhead = 28; + +constexpr uint32_t kMediaSsrc = 83542; +constexpr uint32_t kFlexfecSsrc = 43245; + +// Deep copies |src| to |dst|, but only keeps every Nth packet. +void DeepCopyEveryNthPacket(const ForwardErrorCorrection::PacketList& src, + int n, + ForwardErrorCorrection::PacketList* dst) { + RTC_DCHECK_GT(n, 0); + int i = 0; + for (const auto& packet : src) { + if (i % n == 0) { + dst->emplace_back(new ForwardErrorCorrection::Packet(*packet)); + } + ++i; + } +} + +} // namespace + +using ::testing::Types; + +template <typename ForwardErrorCorrectionType> +class RtpFecTest : public ::testing::Test { + protected: + RtpFecTest() + : random_(0xabcdef123456), + media_packet_generator_( + kRtpHeaderSize, // Minimum packet size. + IP_PACKET_SIZE - kRtpHeaderSize - kTransportOverhead - + fec_.MaxPacketOverhead(), // Maximum packet size. + kMediaSsrc, + &random_) {} + + // Construct |received_packets_|: a subset of the media and FEC packets. + // + // Media packet "i" is lost if media_loss_mask_[i] = 1, received if + // media_loss_mask_[i] = 0. + // FEC packet "i" is lost if fec_loss_mask_[i] = 1, received if + // fec_loss_mask_[i] = 0. + void NetworkReceivedPackets(int* media_loss_mask, int* fec_loss_mask); + + // Add packet from |packet_list| to list of received packets, using the + // |loss_mask|. + // The |packet_list| may be a media packet list (is_fec = false), or a + // FEC packet list (is_fec = true). + template <typename T> + void ReceivedPackets(const T& packet_list, int* loss_mask, bool is_fec); + + // Check for complete recovery after FEC decoding. + bool IsRecoveryComplete(); + + ForwardErrorCorrectionType fec_; + + Random random_; + test::fec::MediaPacketGenerator media_packet_generator_; + + ForwardErrorCorrection::PacketList media_packets_; + std::list<ForwardErrorCorrection::Packet*> generated_fec_packets_; + std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>> + received_packets_; + ForwardErrorCorrection::RecoveredPacketList recovered_packets_; + + int media_loss_mask_[kUlpfecMaxMediaPackets]; + int fec_loss_mask_[kUlpfecMaxMediaPackets]; +}; + +template <typename ForwardErrorCorrectionType> +void RtpFecTest<ForwardErrorCorrectionType>::NetworkReceivedPackets( + int* media_loss_mask, + int* fec_loss_mask) { + constexpr bool kFecPacket = true; + this->received_packets_.clear(); + ReceivedPackets(media_packets_, media_loss_mask, !kFecPacket); + ReceivedPackets(generated_fec_packets_, fec_loss_mask, kFecPacket); +} + +template <typename ForwardErrorCorrectionType> +template <typename PacketListType> +void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets( + const PacketListType& packet_list, + int* loss_mask, + bool is_fec) { + uint16_t fec_seq_num = ForwardErrorCorrectionType::GetFirstFecSeqNum( + media_packet_generator_.GetNextSeqNum()); + int packet_idx = 0; + + for (const auto& packet : packet_list) { + if (loss_mask[packet_idx] == 0) { + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet( + new ForwardErrorCorrection::ReceivedPacket()); + received_packet->pkt = new ForwardErrorCorrection::Packet(); + received_packet->pkt->length = packet->length; + memcpy(received_packet->pkt->data, packet->data, packet->length); + received_packet->is_fec = is_fec; + if (!is_fec) { + received_packet->ssrc = kMediaSsrc; + // For media packets, the sequence number is obtained from the + // RTP header as written by MediaPacketGenerator::ConstructMediaPackets. + received_packet->seq_num = + ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]); + } else { + received_packet->ssrc = ForwardErrorCorrectionType::kFecSsrc; + // For FEC packets, we simulate the sequence numbers differently + // depending on if ULPFEC or FlexFEC is used. See the definition of + // ForwardErrorCorrectionType::GetFirstFecSeqNum. + received_packet->seq_num = fec_seq_num; + } + received_packets_.push_back(std::move(received_packet)); + } + packet_idx++; + // Sequence number of FEC packets are defined as increment by 1 from + // last media packet in frame. + if (is_fec) + fec_seq_num++; + } +} + +template <typename ForwardErrorCorrectionType> +bool RtpFecTest<ForwardErrorCorrectionType>::IsRecoveryComplete() { + // We must have equally many recovered packets as original packets. + if (recovered_packets_.size() != media_packets_.size()) { + return false; + } + + // All recovered packets must be identical to the corresponding + // original packets. + auto cmp = []( + const std::unique_ptr<ForwardErrorCorrection::Packet>& media_packet, + const std::unique_ptr<ForwardErrorCorrection::RecoveredPacket>& + recovered_packet) { + if (media_packet->length != recovered_packet->pkt->length) { + return false; + } + if (memcmp(media_packet->data, recovered_packet->pkt->data, + media_packet->length) != 0) { + return false; + } + return true; + }; + return std::equal(media_packets_.cbegin(), media_packets_.cend(), + recovered_packets_.cbegin(), cmp); +} + +// Define gTest typed test to loop over both ULPFEC and FlexFEC. +// Since the tests now are parameterized, we need to access +// member variables using |this|, thereby enforcing runtime +// resolution. + +class FlexfecForwardErrorCorrection : public ForwardErrorCorrection { + public: + static const uint32_t kFecSsrc = kFlexfecSsrc; + + FlexfecForwardErrorCorrection() + : ForwardErrorCorrection( + std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()), + std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()), + kFecSsrc, + kMediaSsrc) {} + + // For FlexFEC we let the FEC packet sequence numbers be independent of + // the media packet sequence numbers. + static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) { + Random random(0xbe110); + return random.Rand<uint16_t>(); + } +}; + +class UlpfecForwardErrorCorrection : public ForwardErrorCorrection { + public: + static const uint32_t kFecSsrc = kMediaSsrc; + + UlpfecForwardErrorCorrection() + : ForwardErrorCorrection( + std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()), + std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter()), + kFecSsrc, + kMediaSsrc) {} + + // For ULPFEC we assume that the FEC packets are subsequent to the media + // packets in terms of sequence number. + static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) { + return next_media_seq_num; + } +}; + +using FecTypes = + Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>; +TYPED_TEST_CASE(RtpFecTest, FecTypes); + +TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr int kNumMediaPackets = 4; + constexpr uint8_t kProtectionFactor = 60; + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // No packets lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // No packets lost, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); +} + +TYPED_TEST(RtpFecTest, FecRecoveryWithLoss) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr int kNumMediaPackets = 4; + constexpr uint8_t kProtectionFactor = 60; + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // 1 media packet lost + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // One packet lost, one FEC packet, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 2 media packets lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // 2 packets lost, one FEC packet, cannot get complete recovery. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +// Verify that we don't use an old FEC packet for FEC decoding. +TYPED_TEST(RtpFecTest, NoFecRecoveryWithOldFecPacket) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr uint8_t kProtectionFactor = 20; + + // Two frames: first frame (old) with two media packets and 1 FEC packet. + // Third frame (new) with 3 media packets, and no FEC packets. + // + // #0(media) #1(media) #2(FEC) ----Frame 1----- + // #32767(media) 32768(media) 32769(media) ----Frame 2----- + // #65535(media) #0(media) #1(media). ----Frame 3----- + // If we lose either packet 0 or 1 of third frame, FEC decoding should not + // try to decode using "old" FEC packet #2. + + // Construct media packets for first frame, starting at sequence number 0. + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(2, 0); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + // Add FEC packet (seq#2) of this first frame to received list (i.e., assume + // the two media packet were lost). + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, + true); + + // Construct media packets for second frame, with sequence number wrap. + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(3, 32767); + + // Expect 3 media packets for this frame. + EXPECT_EQ(3u, this->media_packets_.size()); + + // No packets lost + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); + + // Construct media packets for third frame, with sequence number wrap. + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(3, 65535); + + // Expect 3 media packets for this frame. + EXPECT_EQ(3u, this->media_packets_.size()); + + // Second media packet lost (seq#0). + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + this->media_loss_mask_[1] = 1; + // Add packets #65535, and #1 to received list. + this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Expect that no decoding is done to get missing packet (seq#0) of third + // frame, using old FEC packet (seq#2) from first (old) frame. So number of + // recovered packets is 5 (0 from first frame, three from second frame, and 2 + // for the third frame, with no packets recovered via FEC). + EXPECT_EQ(5u, this->recovered_packets_.size()); + EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size()); +} + +// Verify we can still recover frame if sequence number wrap occurs within +// the frame and FEC packet following wrap is received after media packets. +TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr uint8_t kProtectionFactor = 20; + + // One frame, with sequence number wrap in media packets. + // -----Frame 1---- + // #65534(media) #65535(media) #0(media) #1(FEC). + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(3, 65534); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // Lose one media packet (seq# 65535). + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); + // Add FEC packet to received list following the media packets. + this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, + true); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Expect 3 media packets in recovered list, and complete recovery. + // Wrap-around won't remove FEC packet, as it follows the wrap. + EXPECT_EQ(3u, this->recovered_packets_.size()); + EXPECT_TRUE(this->IsRecoveryComplete()); +} + +// Sequence number wrap occurs within the ULPFEC packets for the frame. +// Same problem will occur if wrap is within media packets but ULPFEC packet is +// received before the media packets. This may be improved if timing information +// is used to detect old ULPFEC packets. + +// TODO(nisse): There's some logic to discard ULPFEC packets at wrap-around, +// however, that is not actually exercised by this test: When the first FEC +// packet is processed, it results in full recovery of one media packet and the +// FEC packet is forgotten. And then the wraparound isn't noticed when the next +// FEC packet is received. We should fix wraparound handling, which currently +// appears broken, and then figure out how to test it properly. +using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>; +TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameRecovery) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr uint8_t kProtectionFactor = 200; + + // 1 frame: 3 media packets and 2 FEC packets. + // Sequence number wrap in FEC packets. + // -----Frame 1---- + // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC). + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(3, 65532); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 2 FEC packets. + EXPECT_EQ(2u, this->generated_fec_packets_.size()); + + // Lose the last two media packets (seq# 65533, 65534). + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[2] = 1; + this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); + this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, + true); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // The two FEC packets are received and should allow for complete recovery, + // but because of the wrap the first FEC packet will be discarded, and only + // one media packet is recoverable. So expect 2 media packets on recovered + // list and no complete recovery. + EXPECT_EQ(3u, this->recovered_packets_.size()); + EXPECT_EQ(this->recovered_packets_.size(), this->media_packets_.size()); + EXPECT_TRUE(this->IsRecoveryComplete()); +} + +// TODO(brandtr): This test mimics the one above, ensuring that the recovery +// strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC +// does not share the sequence number space with the media, however, having a +// matching recovery strategy may be suboptimal. Study this further. +// TODO(nisse): In this test, recovery based on the first FEC packet fails with +// the log message "The recovered packet had a length larger than a typical IP +// packet, and is thus dropped." This is probably not intended, and needs +// investigation. +using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>; +TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr uint8_t kProtectionFactor = 200; + + // 1 frame: 3 media packets and 2 FEC packets. + // Sequence number wrap in FEC packets. + // -----Frame 1---- + // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC). + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(3, 65532); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 2 FEC packets. + EXPECT_EQ(2u, this->generated_fec_packets_.size()); + + // Overwrite the sequence numbers generated by ConstructMediaPackets, + // to make sure that we do have a wrap. + auto it = this->generated_fec_packets_.begin(); + ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 65535); + ++it; + ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 0); + + // Lose the last two media packets (seq# 65533, 65534). + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[2] = 1; + this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); + this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, + true); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // The two FEC packets are received and should allow for complete recovery, + // but because of the wrap the first FEC packet will be discarded, and only + // one media packet is recoverable. So expect 2 media packets on recovered + // list and no complete recovery. + EXPECT_EQ(2u, this->recovered_packets_.size()); + EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size()); + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +// Verify we can still recover frame if media packets are reordered. +TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr uint8_t kProtectionFactor = 20; + + // One frame: 3 media packets, 1 FEC packet. + // -----Frame 1---- + // #0(media) #1(media) #2(media) #3(FEC). + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(3, 0); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // Lose one media packet (seq# 1). + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + // Reorder received media packets. + auto it0 = this->received_packets_.begin(); + auto it1 = this->received_packets_.begin(); + it1++; + std::swap(*it0, *it1); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Expect 3 media packets in recovered list, and complete recovery. + EXPECT_EQ(3u, this->recovered_packets_.size()); + EXPECT_TRUE(this->IsRecoveryComplete()); +} + +// Verify we can still recover frame if FEC is received before media packets. +TYPED_TEST(RtpFecTest, FecRecoveryWithFecOutOfOrder) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr uint8_t kProtectionFactor = 20; + + // One frame: 3 media packets, 1 FEC packet. + // -----Frame 1---- + // #0(media) #1(media) #2(media) #3(FEC). + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(3, 0); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // Lose one media packet (seq# 1). + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + // Add FEC packet to received list before the media packets. + this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_, + true); + // Add media packets to received list. + this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Expect 3 media packets in recovered list, and complete recovery. + EXPECT_EQ(3u, this->recovered_packets_.size()); + EXPECT_TRUE(this->IsRecoveryComplete()); +} + +// Test 50% protection with random mask type: Two cases are considered: +// a 50% non-consecutive loss which can be fully recovered, and a 50% +// consecutive loss which cannot be fully recovered. +TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percRandomMask) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr int kNumMediaPackets = 4; + constexpr uint8_t kProtectionFactor = 255; + + // Packet Mask for (4,4,0) code, from random mask table. + // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0) + + // media#0 media#1 media#2 media#3 + // fec#0: 1 1 0 0 + // fec#1: 1 0 1 0 + // fec#2: 0 0 1 1 + // fec#3: 0 1 0 1 + // + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskRandom, &this->generated_fec_packets_)); + + // Expect 4 FEC packets. + EXPECT_EQ(4u, this->generated_fec_packets_.size()); + + // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->fec_loss_mask_[0] = 1; + this->media_loss_mask_[0] = 1; + this->media_loss_mask_[2] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 4 consecutive packets lost: media packets 0, 1, 2, 3. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[0] = 1; + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[2] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Cannot get complete recovery for this loss configuration with random mask. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +// Test 50% protection with bursty type: Three cases are considered: +// two 50% consecutive losses which can be fully recovered, and one +// non-consecutive which cannot be fully recovered. +TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr int kNumMediaPackets = 4; + constexpr uint8_t kProtectionFactor = 255; + + // Packet Mask for (4,4,0) code, from bursty mask table. + // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0) + + // media#0 media#1 media#2 media#3 + // fec#0: 1 0 0 0 + // fec#1: 1 1 0 0 + // fec#2: 0 1 1 0 + // fec#3: 0 0 1 1 + // + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 4 FEC packets. + EXPECT_EQ(4u, this->generated_fec_packets_.size()); + + // 4 consecutive packets lost: media packets 0,1,2,3. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[0] = 1; + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[2] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Expect complete recovery for consecutive packet loss <= 50%. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->fec_loss_mask_[0] = 1; + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[2] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Expect complete recovery for consecutive packet loss <= 50%. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->fec_loss_mask_[0] = 1; + this->fec_loss_mask_[3] = 1; + this->media_loss_mask_[0] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Cannot get complete recovery for this loss configuration. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +TYPED_TEST(RtpFecTest, FecRecoveryNoLossUep) { + constexpr int kNumImportantPackets = 2; + constexpr bool kUseUnequalProtection = true; + constexpr int kNumMediaPackets = 4; + constexpr uint8_t kProtectionFactor = 60; + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // No packets lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // No packets lost, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); +} + +TYPED_TEST(RtpFecTest, FecRecoveryWithLossUep) { + constexpr int kNumImportantPackets = 2; + constexpr bool kUseUnequalProtection = true; + constexpr int kNumMediaPackets = 4; + constexpr uint8_t kProtectionFactor = 60; + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // 1 media packet lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // One packet lost, one FEC packet, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 2 media packets lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // 2 packets lost, one FEC packet, cannot get complete recovery. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +// Test 50% protection with random mask type for UEP on. +TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) { + constexpr int kNumImportantPackets = 1; + constexpr bool kUseUnequalProtection = true; + constexpr int kNumMediaPackets = 4; + constexpr uint8_t kProtectionFactor = 255; + + // Packet Mask for (4,4,1) code, from random mask table. + // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1) + + // media#0 media#1 media#2 media#3 + // fec#0: 1 0 0 0 + // fec#1: 1 1 0 0 + // fec#2: 1 0 1 1 + // fec#3: 0 1 1 0 + // + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskRandom, &this->generated_fec_packets_)); + + // Expect 4 FEC packets. + EXPECT_EQ(4u, this->generated_fec_packets_.size()); + + // 4 packets lost: 3 media packets and FEC packet#1 lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->fec_loss_mask_[1] = 1; + this->media_loss_mask_[0] = 1; + this->media_loss_mask_[2] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 5 packets lost: 4 media packets and one FEC packet#2 lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->fec_loss_mask_[2] = 1; + this->media_loss_mask_[0] = 1; + this->media_loss_mask_[1] = 1; + this->media_loss_mask_[2] = 1; + this->media_loss_mask_[3] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Cannot get complete recovery for this loss configuration. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePackets) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr int kNumMediaPackets = 5; + constexpr uint8_t kProtectionFactor = 60; + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + // Create a new temporary packet list for generating FEC packets. + // This list should have every other packet removed. + ForwardErrorCorrection::PacketList protected_media_packets; + DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets); + + EXPECT_EQ( + 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 1 FEC packet. + EXPECT_EQ(1u, this->generated_fec_packets_.size()); + + // 1 protected media packet lost + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[2] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // One packet lost, one FEC packet, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // Unprotected packet lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[1] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Unprotected packet lost. Recovery not possible. + EXPECT_FALSE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 2 media packets lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[0] = 1; + this->media_loss_mask_[2] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // 2 protected packets lost, one FEC packet, cannot get complete recovery. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr int kNumMediaPackets = 21; + uint8_t kProtectionFactor = 127; + + this->media_packets_ = + this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets); + + // Create a new temporary packet list for generating FEC packets. + // This list should have every other packet removed. + ForwardErrorCorrection::PacketList protected_media_packets; + DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets); + + // Zero column insertion will have to extend the size of the packet + // mask since the number of actual packets are 21, while the number + // of protected packets are 11. + EXPECT_EQ( + 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 5 FEC packet. + EXPECT_EQ(5u, this->generated_fec_packets_.size()); + + // Last protected media packet lost + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[kNumMediaPackets - 1] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // One packet lost, one FEC packet, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // Last unprotected packet lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[kNumMediaPackets - 2] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Unprotected packet lost. Recovery not possible. + EXPECT_FALSE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 6 media packets lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[kNumMediaPackets - 11] = 1; + this->media_loss_mask_[kNumMediaPackets - 9] = 1; + this->media_loss_mask_[kNumMediaPackets - 7] = 1; + this->media_loss_mask_[kNumMediaPackets - 5] = 1; + this->media_loss_mask_[kNumMediaPackets - 3] = 1; + this->media_loss_mask_[kNumMediaPackets - 1] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // 5 protected packets lost, one FEC packet, cannot get complete recovery. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) { + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr int kNumMediaPackets = 21; + uint8_t kProtectionFactor = 127; + + this->media_packets_ = this->media_packet_generator_.ConstructMediaPackets( + kNumMediaPackets, 0xFFFF - 5); + + // Create a new temporary packet list for generating FEC packets. + // This list should have every other packet removed. + ForwardErrorCorrection::PacketList protected_media_packets; + DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets); + + // Zero column insertion will have to extend the size of the packet + // mask since the number of actual packets are 21, while the number + // of protected packets are 11. + EXPECT_EQ( + 0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor, + kNumImportantPackets, kUseUnequalProtection, + kFecMaskBursty, &this->generated_fec_packets_)); + + // Expect 5 FEC packet. + EXPECT_EQ(5u, this->generated_fec_packets_.size()); + + // Last protected media packet lost + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[kNumMediaPackets - 1] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // One packet lost, one FEC packet, expect complete recovery. + EXPECT_TRUE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // Last unprotected packet lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[kNumMediaPackets - 2] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // Unprotected packet lost. Recovery not possible. + EXPECT_FALSE(this->IsRecoveryComplete()); + this->recovered_packets_.clear(); + + // 6 media packets lost. + memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_)); + memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_)); + this->media_loss_mask_[kNumMediaPackets - 11] = 1; + this->media_loss_mask_[kNumMediaPackets - 9] = 1; + this->media_loss_mask_[kNumMediaPackets - 7] = 1; + this->media_loss_mask_[kNumMediaPackets - 5] = 1; + this->media_loss_mask_[kNumMediaPackets - 3] = 1; + this->media_loss_mask_[kNumMediaPackets - 1] = 1; + this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_); + + for (const auto& received_packet : this->received_packets_) { + this->fec_.DecodeFec(*received_packet, + &this->recovered_packets_); + } + + // 5 protected packets lost, one FEC packet, cannot get complete recovery. + EXPECT_FALSE(this->IsRecoveryComplete()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.cc new file mode 100644 index 0000000000..05dc900233 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.cc @@ -0,0 +1,63 @@ +/* + * 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/rtp_rtcp/source/rtp_format.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/rtp_format_h264.h" +#include "modules/rtp_rtcp/source/rtp_format_video_generic.h" +#include "modules/rtp_rtcp/source/rtp_format_vp8.h" +#include "modules/rtp_rtcp/source/rtp_format_vp9.h" + +namespace webrtc { +RtpPacketizer* RtpPacketizer::Create(RtpVideoCodecTypes type, + size_t max_payload_len, + size_t last_packet_reduction_len, + const RTPVideoTypeHeader* rtp_type_header, + FrameType frame_type) { + switch (type) { + case kRtpVideoH264: + RTC_CHECK(rtp_type_header); + return new RtpPacketizerH264(max_payload_len, last_packet_reduction_len, + rtp_type_header->H264.packetization_mode); + case kRtpVideoVp8: + RTC_CHECK(rtp_type_header); + return new RtpPacketizerVp8(rtp_type_header->VP8, max_payload_len, + last_packet_reduction_len); + case kRtpVideoVp9: + RTC_CHECK(rtp_type_header); + return new RtpPacketizerVp9(rtp_type_header->VP9, max_payload_len, + last_packet_reduction_len); + case kRtpVideoGeneric: + return new RtpPacketizerGeneric(frame_type, max_payload_len, + last_packet_reduction_len); + case kRtpVideoNone: + RTC_NOTREACHED(); + } + return nullptr; +} + +RtpDepacketizer* RtpDepacketizer::Create(RtpVideoCodecTypes type) { + switch (type) { + case kRtpVideoH264: + return new RtpDepacketizerH264(); + case kRtpVideoVp8: + return new RtpDepacketizerVp8(); + case kRtpVideoVp9: + return new RtpDepacketizerVp9(); + case kRtpVideoGeneric: + return new RtpDepacketizerGeneric(); + case kRtpVideoNone: + assert(false); + } + return nullptr; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.h new file mode 100644 index 0000000000..ea098da710 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.h @@ -0,0 +1,70 @@ +/* + * 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_RTP_RTCP_SOURCE_RTP_FORMAT_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_ + +#include <string> + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/constructormagic.h" + +namespace webrtc { +class RtpPacketToSend; + +class RtpPacketizer { + public: + static RtpPacketizer* Create(RtpVideoCodecTypes type, + size_t max_payload_len, + size_t last_packet_reduction_len, + const RTPVideoTypeHeader* rtp_type_header, + FrameType frame_type); + + virtual ~RtpPacketizer() {} + + // Returns total number of packets which would be produced by the packetizer. + virtual size_t SetPayloadData( + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) = 0; + + // Get the next payload with payload header. + // Write payload and set marker bit of the |packet|. + // Returns true on success, false otherwise. + virtual bool NextPacket(RtpPacketToSend* packet) = 0; + + virtual std::string ToString() = 0; +}; + +// TODO(sprang): Update the depacketizer to return a std::unqie_ptr with a copy +// of the parsed payload, rather than just a pointer into the incoming buffer. +// This way we can move some parsing out from the jitter buffer into here, and +// the jitter buffer can just store that pointer rather than doing a copy there. +class RtpDepacketizer { + public: + struct ParsedPayload { + const uint8_t* payload; + size_t payload_length; + FrameType frame_type; + RTPTypeHeader type; + }; + + static RtpDepacketizer* Create(RtpVideoCodecTypes type); + + virtual ~RtpDepacketizer() {} + + // Parses the RTP payload, parsed result will be saved in |parsed_payload|. + virtual bool Parse(ParsedPayload* parsed_payload, + const uint8_t* payload_data, + size_t payload_data_length) = 0; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc new file mode 100644 index 0000000000..57a79557e9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc @@ -0,0 +1,669 @@ +/* + * 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/rtp_rtcp/source/rtp_format_h264.h" + +#include <string.h> +#include <memory> +#include <utility> +#include <vector> + +#include "common_video/h264/h264_common.h" +#include "common_video/h264/pps_parser.h" +#include "common_video/h264/sps_parser.h" +#include "common_video/h264/sps_vui_rewriter.h" +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/metrics.h" + +namespace webrtc { +namespace { + +static const size_t kNalHeaderSize = 1; +static const size_t kFuAHeaderSize = 2; +static const size_t kLengthFieldSize = 2; +static const size_t kStapAHeaderSize = kNalHeaderSize + kLengthFieldSize; + +static const char* kSpsValidHistogramName = "WebRTC.Video.H264.SpsValid"; +enum SpsValidEvent { + kReceivedSpsPocOk = 0, + kReceivedSpsVuiOk = 1, + kReceivedSpsRewritten = 2, + kReceivedSpsParseFailure = 3, + kSentSpsPocOk = 4, + kSentSpsVuiOk = 5, + kSentSpsRewritten = 6, + kSentSpsParseFailure = 7, + kSpsRewrittenMax = 8 +}; + +// Bit masks for FU (A and B) indicators. +enum NalDefs : uint8_t { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F }; + +// Bit masks for FU (A and B) headers. +enum FuDefs : uint8_t { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 }; + +// TODO(pbos): Avoid parsing this here as well as inside the jitter buffer. +bool ParseStapAStartOffsets(const uint8_t* nalu_ptr, + size_t length_remaining, + std::vector<size_t>* offsets) { + size_t offset = 0; + while (length_remaining > 0) { + // Buffer doesn't contain room for additional nalu length. + if (length_remaining < sizeof(uint16_t)) + return false; + uint16_t nalu_size = ByteReader<uint16_t>::ReadBigEndian(nalu_ptr); + nalu_ptr += sizeof(uint16_t); + length_remaining -= sizeof(uint16_t); + if (nalu_size > length_remaining) + return false; + nalu_ptr += nalu_size; + length_remaining -= nalu_size; + + offsets->push_back(offset + kStapAHeaderSize); + offset += kLengthFieldSize + nalu_size; + } + return true; +} + +} // namespace + +RtpPacketizerH264::RtpPacketizerH264(size_t max_payload_len, + size_t last_packet_reduction_len, + H264PacketizationMode packetization_mode) + : max_payload_len_(max_payload_len), + last_packet_reduction_len_(last_packet_reduction_len), + num_packets_left_(0), + packetization_mode_(packetization_mode) { + // Guard against uninitialized memory in packetization_mode. + RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved || + packetization_mode == H264PacketizationMode::SingleNalUnit); + RTC_CHECK_GT(max_payload_len, last_packet_reduction_len); +} + +RtpPacketizerH264::~RtpPacketizerH264() { +} + +RtpPacketizerH264::Fragment::Fragment(const uint8_t* buffer, size_t length) + : buffer(buffer), length(length) {} +RtpPacketizerH264::Fragment::Fragment(const Fragment& fragment) + : buffer(fragment.buffer), length(fragment.length) {} + +size_t RtpPacketizerH264::SetPayloadData( + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) { + RTC_DCHECK(packets_.empty()); + RTC_DCHECK(input_fragments_.empty()); + RTC_DCHECK(fragmentation); + for (int i = 0; i < fragmentation->fragmentationVectorSize; ++i) { + const uint8_t* buffer = + &payload_data[fragmentation->fragmentationOffset[i]]; + size_t length = fragmentation->fragmentationLength[i]; + + bool updated_sps = false; + H264::NaluType nalu_type = H264::ParseNaluType(buffer[0]); + if (nalu_type == H264::NaluType::kSps) { + // Check if stream uses picture order count type 0, and if so rewrite it + // to enable faster decoding. Streams in that format incur additional + // delay because it allows decode order to differ from render order. + // The mechanism used is to rewrite (edit or add) the SPS's VUI to contain + // restrictions on the maximum number of reordered pictures. This reduces + // latency significantly, though it still adds about a frame of latency to + // decoding. + // Note that we do this rewriting both here (send side, in order to + // protect legacy receive clients) and below in + // RtpDepacketizerH264::ParseSingleNalu (receive side, in orderer to + // protect us from unknown or legacy send clients). + + rtc::Optional<SpsParser::SpsState> sps; + + std::unique_ptr<rtc::Buffer> output_buffer(new rtc::Buffer()); + // Add the type header to the output buffer first, so that the rewriter + // can append modified payload on top of that. + output_buffer->AppendData(buffer[0]); + SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps( + buffer + H264::kNaluTypeSize, length - H264::kNaluTypeSize, &sps, + output_buffer.get()); + + switch (result) { + case SpsVuiRewriter::ParseResult::kVuiRewritten: + input_fragments_.push_back( + Fragment(output_buffer->data(), output_buffer->size())); + input_fragments_.rbegin()->tmp_buffer = std::move(output_buffer); + updated_sps = true; + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kSentSpsRewritten, + SpsValidEvent::kSpsRewrittenMax); + break; + case SpsVuiRewriter::ParseResult::kPocOk: + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kSentSpsPocOk, + SpsValidEvent::kSpsRewrittenMax); + break; + case SpsVuiRewriter::ParseResult::kVuiOk: + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kSentSpsVuiOk, + SpsValidEvent::kSpsRewrittenMax); + break; + case SpsVuiRewriter::ParseResult::kFailure: + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kSentSpsParseFailure, + SpsValidEvent::kSpsRewrittenMax); + break; + } + } + + if (!updated_sps) + input_fragments_.push_back(Fragment(buffer, length)); + } + GeneratePackets(); + return num_packets_left_; +} + +void RtpPacketizerH264::GeneratePackets() { + for (size_t i = 0; i < input_fragments_.size();) { + switch (packetization_mode_) { + case H264PacketizationMode::SingleNalUnit: + PacketizeSingleNalu(i); + ++i; + break; + case H264PacketizationMode::NonInterleaved: + size_t fragment_len = input_fragments_[i].length; + if (i + 1 == input_fragments_.size()) { + // Pretend that last fragment is larger instead of making last packet + // smaller. + fragment_len += last_packet_reduction_len_; + } + if (fragment_len > max_payload_len_) { + PacketizeFuA(i); + ++i; + } else { + i = PacketizeStapA(i); + } + break; + } + } +} + +void RtpPacketizerH264::PacketizeFuA(size_t fragment_index) { + // Fragment payload into packets (FU-A). + // Strip out the original header and leave room for the FU-A header. + const Fragment& fragment = input_fragments_[fragment_index]; + bool is_last_fragment = fragment_index + 1 == input_fragments_.size(); + size_t payload_left = fragment.length - kNalHeaderSize; + size_t offset = kNalHeaderSize; + size_t per_packet_capacity = max_payload_len_ - kFuAHeaderSize; + + // Instead of making the last packet smaller we pretend that all packets are + // of the same size but we write additional virtual payload to the last + // packet. + size_t extra_len = is_last_fragment ? last_packet_reduction_len_ : 0; + + // Integer divisions with rounding up. Minimal number of packets to fit all + // payload and virtual payload. + size_t num_packets = (payload_left + extra_len + (per_packet_capacity - 1)) / + per_packet_capacity; + // Bytes per packet. Average rounded down. + size_t payload_per_packet = (payload_left + extra_len) / num_packets; + // We make several first packets to be 1 bytes smaller than the rest. + // i.e 14 bytes splitted in 4 packets would be 3+3+4+4. + size_t num_larger_packets = (payload_left + extra_len) % num_packets; + + num_packets_left_ += num_packets; + while (payload_left > 0) { + // Increase payload per packet at the right time. + if (num_packets == num_larger_packets) + ++payload_per_packet; + size_t packet_length = payload_per_packet; + if (payload_left <= packet_length) { // Last portion of the payload + packet_length = payload_left; + // One additional packet may be used for extensions in the last packet. + // Together with last payload packet there may be at most 2 of them. + RTC_DCHECK_LE(num_packets, 2); + if (num_packets == 2) { + // Whole payload fits in the first num_packets-1 packets but extra + // packet is used for virtual payload. Leave at least one byte of data + // for the last packet. + --packet_length; + } + } + RTC_CHECK_GT(packet_length, 0); + packets_.push(PacketUnit(Fragment(fragment.buffer + offset, packet_length), + offset - kNalHeaderSize == 0, + payload_left == packet_length, false, + fragment.buffer[0])); + offset += packet_length; + payload_left -= packet_length; + --num_packets; + } + RTC_CHECK_EQ(0, payload_left); +} + +size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) { + // Aggregate fragments into one packet (STAP-A). + size_t payload_size_left = max_payload_len_; + int aggregated_fragments = 0; + size_t fragment_headers_length = 0; + const Fragment* fragment = &input_fragments_[fragment_index]; + RTC_CHECK_GE(payload_size_left, fragment->length); + ++num_packets_left_; + while (payload_size_left >= fragment->length + fragment_headers_length && + (fragment_index + 1 < input_fragments_.size() || + payload_size_left >= fragment->length + fragment_headers_length + + last_packet_reduction_len_)) { + RTC_CHECK_GT(fragment->length, 0); + packets_.push(PacketUnit(*fragment, aggregated_fragments == 0, false, true, + fragment->buffer[0])); + payload_size_left -= fragment->length; + payload_size_left -= fragment_headers_length; + + fragment_headers_length = kLengthFieldSize; + // If we are going to try to aggregate more fragments into this packet + // we need to add the STAP-A NALU header and a length field for the first + // NALU of this packet. + if (aggregated_fragments == 0) + fragment_headers_length += kNalHeaderSize + kLengthFieldSize; + ++aggregated_fragments; + + // Next fragment. + ++fragment_index; + if (fragment_index == input_fragments_.size()) + break; + fragment = &input_fragments_[fragment_index]; + } + RTC_CHECK_GT(aggregated_fragments, 0); + packets_.back().last_fragment = true; + return fragment_index; +} + +void RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) { + // Add a single NALU to the queue, no aggregation. + size_t payload_size_left = max_payload_len_; + if (fragment_index + 1 == input_fragments_.size()) + payload_size_left -= last_packet_reduction_len_; + const Fragment* fragment = &input_fragments_[fragment_index]; + RTC_CHECK_GE(payload_size_left, fragment->length) + << "Payload size left " << payload_size_left << ", fragment length " + << fragment->length << ", packetization mode " << packetization_mode_; + RTC_CHECK_GT(fragment->length, 0u); + packets_.push(PacketUnit(*fragment, true /* first */, true /* last */, + false /* aggregated */, fragment->buffer[0])); + ++num_packets_left_; +} + +bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet) { + RTC_DCHECK(rtp_packet); + if (packets_.empty()) { + return false; + } + + PacketUnit packet = packets_.front(); + if (packet.first_fragment && packet.last_fragment) { + // Single NAL unit packet. + size_t bytes_to_send = packet.source_fragment.length; + uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send); + memcpy(buffer, packet.source_fragment.buffer, bytes_to_send); + packets_.pop(); + input_fragments_.pop_front(); + } else if (packet.aggregated) { + RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); + bool is_last_packet = num_packets_left_ == 1; + NextAggregatePacket(rtp_packet, is_last_packet); + } else { + RTC_CHECK_EQ(H264PacketizationMode::NonInterleaved, packetization_mode_); + NextFragmentPacket(rtp_packet); + } + RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_); + if (packets_.empty()) { + RTC_DCHECK_LE(rtp_packet->payload_size(), + max_payload_len_ - last_packet_reduction_len_); + } + rtp_packet->SetMarker(packets_.empty()); + --num_packets_left_; + return true; +} + +void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet, + bool last) { + uint8_t* buffer = rtp_packet->AllocatePayload( + last ? max_payload_len_ - last_packet_reduction_len_ : max_payload_len_); + RTC_DCHECK(buffer); + PacketUnit* packet = &packets_.front(); + RTC_CHECK(packet->first_fragment); + // STAP-A NALU header. + buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA; + size_t index = kNalHeaderSize; + bool is_last_fragment = packet->last_fragment; + while (packet->aggregated) { + const Fragment& fragment = packet->source_fragment; + // Add NAL unit length field. + ByteWriter<uint16_t>::WriteBigEndian(&buffer[index], fragment.length); + index += kLengthFieldSize; + // Add NAL unit. + memcpy(&buffer[index], fragment.buffer, fragment.length); + index += fragment.length; + packets_.pop(); + input_fragments_.pop_front(); + if (is_last_fragment) + break; + packet = &packets_.front(); + is_last_fragment = packet->last_fragment; + } + RTC_CHECK(is_last_fragment); + rtp_packet->SetPayloadSize(index); +} + +void RtpPacketizerH264::NextFragmentPacket(RtpPacketToSend* rtp_packet) { + PacketUnit* packet = &packets_.front(); + // NAL unit fragmented over multiple packets (FU-A). + // We do not send original NALU header, so it will be replaced by the + // FU indicator header of the first packet. + uint8_t fu_indicator = + (packet->header & (kFBit | kNriMask)) | H264::NaluType::kFuA; + uint8_t fu_header = 0; + + // S | E | R | 5 bit type. + fu_header |= (packet->first_fragment ? kSBit : 0); + fu_header |= (packet->last_fragment ? kEBit : 0); + uint8_t type = packet->header & kTypeMask; + fu_header |= type; + const Fragment& fragment = packet->source_fragment; + uint8_t* buffer = + rtp_packet->AllocatePayload(kFuAHeaderSize + fragment.length); + buffer[0] = fu_indicator; + buffer[1] = fu_header; + memcpy(buffer + kFuAHeaderSize, fragment.buffer, fragment.length); + if (packet->last_fragment) + input_fragments_.pop_front(); + packets_.pop(); +} + +std::string RtpPacketizerH264::ToString() { + return "RtpPacketizerH264"; +} + +RtpDepacketizerH264::RtpDepacketizerH264() : offset_(0), length_(0) {} +RtpDepacketizerH264::~RtpDepacketizerH264() {} + +bool RtpDepacketizerH264::Parse(ParsedPayload* parsed_payload, + const uint8_t* payload_data, + size_t payload_data_length) { + RTC_CHECK(parsed_payload != nullptr); + if (payload_data_length == 0) { + RTC_LOG(LS_ERROR) << "Empty payload."; + return false; + } + + offset_ = 0; + length_ = payload_data_length; + modified_buffer_.reset(); + + uint8_t nal_type = payload_data[0] & kTypeMask; + parsed_payload->type.Video.codecHeader.H264.nalus_length = 0; + if (nal_type == H264::NaluType::kFuA) { + // Fragmented NAL units (FU-A). + if (!ParseFuaNalu(parsed_payload, payload_data)) + return false; + } else { + // We handle STAP-A and single NALU's the same way here. The jitter buffer + // will depacketize the STAP-A into NAL units later. + // TODO(sprang): Parse STAP-A offsets here and store in fragmentation vec. + if (!ProcessStapAOrSingleNalu(parsed_payload, payload_data)) + return false; + } + + const uint8_t* payload = + modified_buffer_ ? modified_buffer_->data() : payload_data; + + parsed_payload->payload = payload + offset_; + parsed_payload->payload_length = length_; + return true; +} + +bool RtpDepacketizerH264::ProcessStapAOrSingleNalu( + ParsedPayload* parsed_payload, + const uint8_t* payload_data) { + parsed_payload->type.Video.width = 0; + parsed_payload->type.Video.height = 0; + parsed_payload->type.Video.codec = kRtpVideoH264; + parsed_payload->type.Video.is_first_packet_in_frame = true; + RTPVideoHeaderH264* h264_header = + &parsed_payload->type.Video.codecHeader.H264; + + const uint8_t* nalu_start = payload_data + kNalHeaderSize; + const size_t nalu_length = length_ - kNalHeaderSize; + uint8_t nal_type = payload_data[0] & kTypeMask; + std::vector<size_t> nalu_start_offsets; + if (nal_type == H264::NaluType::kStapA) { + // Skip the StapA header (StapA NAL type + length). + if (length_ <= kStapAHeaderSize) { + RTC_LOG(LS_ERROR) << "StapA header truncated."; + return false; + } + + if (!ParseStapAStartOffsets(nalu_start, nalu_length, &nalu_start_offsets)) { + RTC_LOG(LS_ERROR) << "StapA packet with incorrect NALU packet lengths."; + return false; + } + + h264_header->packetization_type = kH264StapA; + nal_type = payload_data[kStapAHeaderSize] & kTypeMask; + } else { + h264_header->packetization_type = kH264SingleNalu; + nalu_start_offsets.push_back(0); + } + h264_header->nalu_type = nal_type; + parsed_payload->frame_type = kVideoFrameDelta; + + nalu_start_offsets.push_back(length_ + kLengthFieldSize); // End offset. + for (size_t i = 0; i < nalu_start_offsets.size() - 1; ++i) { + size_t start_offset = nalu_start_offsets[i]; + // End offset is actually start offset for next unit, excluding length field + // so remove that from this units length. + size_t end_offset = nalu_start_offsets[i + 1] - kLengthFieldSize; + if (end_offset - start_offset < H264::kNaluTypeSize) { + RTC_LOG(LS_ERROR) << "STAP-A packet too short"; + return false; + } + + NaluInfo nalu; + nalu.type = payload_data[start_offset] & kTypeMask; + nalu.sps_id = -1; + nalu.pps_id = -1; + start_offset += H264::kNaluTypeSize; + + switch (nalu.type) { + case H264::NaluType::kSps: { + // Check if VUI is present in SPS and if it needs to be modified to + // avoid + // excessive decoder latency. + + // Copy any previous data first (likely just the first header). + std::unique_ptr<rtc::Buffer> output_buffer(new rtc::Buffer()); + if (start_offset) + output_buffer->AppendData(payload_data, start_offset); + + rtc::Optional<SpsParser::SpsState> sps; + + SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps( + &payload_data[start_offset], end_offset - start_offset, &sps, + output_buffer.get()); + switch (result) { + case SpsVuiRewriter::ParseResult::kVuiRewritten: + if (modified_buffer_) { + RTC_LOG(LS_WARNING) + << "More than one H264 SPS NAL units needing " + "rewriting found within a single STAP-A packet. " + "Keeping the first and rewriting the last."; + } + + // Rewrite length field to new SPS size. + if (h264_header->packetization_type == kH264StapA) { + size_t length_field_offset = + start_offset - (H264::kNaluTypeSize + kLengthFieldSize); + // Stap-A Length includes payload data and type header. + size_t rewritten_size = + output_buffer->size() - start_offset + H264::kNaluTypeSize; + ByteWriter<uint16_t>::WriteBigEndian( + &(*output_buffer)[length_field_offset], rewritten_size); + } + + // Append rest of packet. + output_buffer->AppendData( + &payload_data[end_offset], + nalu_length + kNalHeaderSize - end_offset); + + modified_buffer_ = std::move(output_buffer); + length_ = modified_buffer_->size(); + + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kReceivedSpsRewritten, + SpsValidEvent::kSpsRewrittenMax); + break; + case SpsVuiRewriter::ParseResult::kPocOk: + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kReceivedSpsPocOk, + SpsValidEvent::kSpsRewrittenMax); + break; + case SpsVuiRewriter::ParseResult::kVuiOk: + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kReceivedSpsVuiOk, + SpsValidEvent::kSpsRewrittenMax); + break; + case SpsVuiRewriter::ParseResult::kFailure: + RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName, + SpsValidEvent::kReceivedSpsParseFailure, + SpsValidEvent::kSpsRewrittenMax); + break; + } + + if (sps) { + parsed_payload->type.Video.width = sps->width; + parsed_payload->type.Video.height = sps->height; + nalu.sps_id = sps->id; + } else { + RTC_LOG(LS_WARNING) << "Failed to parse SPS id from SPS slice."; + } + parsed_payload->frame_type = kVideoFrameKey; + break; + } + case H264::NaluType::kPps: { + uint32_t pps_id; + uint32_t sps_id; + if (PpsParser::ParsePpsIds(&payload_data[start_offset], + end_offset - start_offset, &pps_id, + &sps_id)) { + nalu.pps_id = pps_id; + nalu.sps_id = sps_id; + } else { + RTC_LOG(LS_WARNING) + << "Failed to parse PPS id and SPS id from PPS slice."; + } + break; + } + case H264::NaluType::kIdr: + parsed_payload->frame_type = kVideoFrameKey; + FALLTHROUGH(); + case H264::NaluType::kSlice: { + rtc::Optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice( + &payload_data[start_offset], end_offset - start_offset); + if (pps_id) { + nalu.pps_id = *pps_id; + } else { + RTC_LOG(LS_WARNING) << "Failed to parse PPS id from slice of type: " + << static_cast<int>(nalu.type); + } + break; + } + // Slices below don't contain SPS or PPS ids. + case H264::NaluType::kAud: + case H264::NaluType::kEndOfSequence: + case H264::NaluType::kEndOfStream: + case H264::NaluType::kFiller: + case H264::NaluType::kSei: + break; + case H264::NaluType::kStapA: + case H264::NaluType::kFuA: + RTC_LOG(LS_WARNING) << "Unexpected STAP-A or FU-A received."; + return false; + } + RTPVideoHeaderH264* h264 = &parsed_payload->type.Video.codecHeader.H264; + if (h264->nalus_length == kMaxNalusPerPacket) { + RTC_LOG(LS_WARNING) + << "Received packet containing more than " << kMaxNalusPerPacket + << " NAL units. Will not keep track sps and pps ids for all of them."; + } else { + h264->nalus[h264->nalus_length++] = nalu; + } + } + + return true; +} + +bool RtpDepacketizerH264::ParseFuaNalu( + RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* payload_data) { + if (length_ < kFuAHeaderSize) { + RTC_LOG(LS_ERROR) << "FU-A NAL units truncated."; + return false; + } + uint8_t fnri = payload_data[0] & (kFBit | kNriMask); + uint8_t original_nal_type = payload_data[1] & kTypeMask; + bool first_fragment = (payload_data[1] & kSBit) > 0; + NaluInfo nalu; + nalu.type = original_nal_type; + nalu.sps_id = -1; + nalu.pps_id = -1; + if (first_fragment) { + offset_ = 0; + length_ -= kNalHeaderSize; + rtc::Optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice( + payload_data + 2 * kNalHeaderSize, length_ - kNalHeaderSize); + if (pps_id) { + nalu.pps_id = *pps_id; + } else { + RTC_LOG(LS_WARNING) + << "Failed to parse PPS from first fragment of FU-A NAL " + "unit with original type: " + << static_cast<int>(nalu.type); + } + uint8_t original_nal_header = fnri | original_nal_type; + modified_buffer_.reset(new rtc::Buffer()); + modified_buffer_->AppendData(payload_data + kNalHeaderSize, length_); + (*modified_buffer_)[0] = original_nal_header; + } else { + offset_ = kFuAHeaderSize; + length_ -= kFuAHeaderSize; + } + + if (original_nal_type == H264::NaluType::kIdr) { + parsed_payload->frame_type = kVideoFrameKey; + } else { + parsed_payload->frame_type = kVideoFrameDelta; + } + parsed_payload->type.Video.width = 0; + parsed_payload->type.Video.height = 0; + parsed_payload->type.Video.codec = kRtpVideoH264; + parsed_payload->type.Video.is_first_packet_in_frame = first_fragment; + RTPVideoHeaderH264* h264 = &parsed_payload->type.Video.codecHeader.H264; + h264->packetization_type = kH264FuA; + h264->nalu_type = original_nal_type; + if (first_fragment) { + h264->nalus[h264->nalus_length] = nalu; + h264->nalus_length = 1; + } + return true; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h new file mode 100644 index 0000000000..5b6fe02295 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h @@ -0,0 +1,120 @@ +/* + * 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_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_ + +#include <deque> +#include <memory> +#include <queue> +#include <string> + +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "rtc_base/buffer.h" +#include "rtc_base/constructormagic.h" + +namespace webrtc { + +class RtpPacketizerH264 : public RtpPacketizer { + public: + // Initialize with payload from encoder. + // The payload_data must be exactly one encoded H264 frame. + RtpPacketizerH264(size_t max_payload_len, + size_t last_packet_reduction_len, + H264PacketizationMode packetization_mode); + + virtual ~RtpPacketizerH264(); + + size_t SetPayloadData(const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) override; + + // Get the next payload with H264 payload header. + // Write payload and set marker bit of the |packet|. + // Returns true on success, false otherwise. + bool NextPacket(RtpPacketToSend* rtp_packet) override; + + std::string ToString() override; + + private: + // Input fragments (NAL units), with an optionally owned temporary buffer, + // used in case the fragment gets modified. + struct Fragment { + Fragment(const uint8_t* buffer, size_t length); + explicit Fragment(const Fragment& fragment); + const uint8_t* buffer = nullptr; + size_t length = 0; + std::unique_ptr<rtc::Buffer> tmp_buffer; + }; + + // A packet unit (H264 packet), to be put into an RTP packet: + // If a NAL unit is too large for an RTP packet, this packet unit will + // represent a FU-A packet of a single fragment of the NAL unit. + // If a NAL unit is small enough to fit within a single RTP packet, this + // packet unit may represent a single NAL unit or a STAP-A packet, of which + // there may be multiple in a single RTP packet (if so, aggregated = true). + struct PacketUnit { + PacketUnit(const Fragment& source_fragment, + bool first_fragment, + bool last_fragment, + bool aggregated, + uint8_t header) + : source_fragment(source_fragment), + first_fragment(first_fragment), + last_fragment(last_fragment), + aggregated(aggregated), + header(header) {} + + const Fragment source_fragment; + bool first_fragment; + bool last_fragment; + bool aggregated; + uint8_t header; + }; + + void GeneratePackets(); + void PacketizeFuA(size_t fragment_index); + size_t PacketizeStapA(size_t fragment_index); + void PacketizeSingleNalu(size_t fragment_index); + void NextAggregatePacket(RtpPacketToSend* rtp_packet, bool last); + void NextFragmentPacket(RtpPacketToSend* rtp_packet); + + const size_t max_payload_len_; + const size_t last_packet_reduction_len_; + size_t num_packets_left_; + const H264PacketizationMode packetization_mode_; + std::deque<Fragment> input_fragments_; + std::queue<PacketUnit> packets_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerH264); +}; + +// Depacketizer for H264. +class RtpDepacketizerH264 : public RtpDepacketizer { + public: + RtpDepacketizerH264(); + virtual ~RtpDepacketizerH264(); + + bool Parse(ParsedPayload* parsed_payload, + const uint8_t* payload_data, + size_t payload_data_length) override; + + private: + bool ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* payload_data); + bool ProcessStapAOrSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* payload_data); + + size_t offset_; + size_t length_; + std::unique_ptr<rtc::Buffer> modified_buffer_; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc new file mode 100644 index 0000000000..0eef2bcd85 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc @@ -0,0 +1,946 @@ +/* + * 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 <memory> +#include <vector> + +#include "api/array_view.h" +#include "common_video/h264/h264_common.h" +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::ElementsAreArray; + +constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; +const size_t kMaxPayloadSize = 1200; +const size_t kLengthFieldLength = 2; + +enum Nalu { + kSlice = 1, + kIdr = 5, + kSei = 6, + kSps = 7, + kPps = 8, + kStapA = 24, + kFuA = 28 +}; + +static const size_t kNalHeaderSize = 1; +static const size_t kFuAHeaderSize = 2; + +// Bit masks for FU (A and B) indicators. +enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F }; + +// Bit masks for FU (A and B) headers. +enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 }; + +void CreateThreeFragments(RTPFragmentationHeader* fragmentation, + size_t frameSize, + size_t payloadOffset) { + fragmentation->VerifyAndAllocateFragmentationHeader(3); + fragmentation->fragmentationOffset[0] = 0; + fragmentation->fragmentationLength[0] = 2; + fragmentation->fragmentationOffset[1] = 2; + fragmentation->fragmentationLength[1] = 2; + fragmentation->fragmentationOffset[2] = 4; + fragmentation->fragmentationLength[2] = + kNalHeaderSize + frameSize - payloadOffset; +} + +RtpPacketizer* CreateH264Packetizer(H264PacketizationMode mode, + size_t max_payload_size, + size_t last_packet_reduction) { + RTPVideoTypeHeader type_header; + type_header.H264.packetization_mode = mode; + return RtpPacketizer::Create(kRtpVideoH264, max_payload_size, + last_packet_reduction, &type_header, + kEmptyFrame); +} + +void VerifyFua(size_t fua_index, + const uint8_t* expected_payload, + int offset, + rtc::ArrayView<const uint8_t> packet, + const std::vector<size_t>& expected_sizes) { + ASSERT_EQ(expected_sizes[fua_index] + kFuAHeaderSize, packet.size()) + << "FUA index: " << fua_index; + const uint8_t kFuIndicator = 0x1C; // F=0, NRI=0, Type=28. + EXPECT_EQ(kFuIndicator, packet[0]) << "FUA index: " << fua_index; + bool should_be_last_fua = (fua_index == expected_sizes.size() - 1); + uint8_t fu_header = 0; + if (fua_index == 0) + fu_header = 0x85; // S=1, E=0, R=0, Type=5. + else if (should_be_last_fua) + fu_header = 0x45; // S=0, E=1, R=0, Type=5. + else + fu_header = 0x05; // S=0, E=0, R=0, Type=5. + EXPECT_EQ(fu_header, packet[1]) << "FUA index: " << fua_index; + std::vector<uint8_t> expected_packet_payload( + &expected_payload[offset], + &expected_payload[offset + expected_sizes[fua_index]]); + EXPECT_THAT(expected_packet_payload, + ElementsAreArray(&packet[2], expected_sizes[fua_index])) + << "FUA index: " << fua_index; +} + +void TestFua(size_t frame_size, + size_t max_payload_size, + size_t last_packet_reduction, + const std::vector<size_t>& expected_sizes) { + std::unique_ptr<uint8_t[]> frame; + frame.reset(new uint8_t[frame_size]); + frame[0] = 0x05; // F=0, NRI=0, Type=5. + for (size_t i = 0; i < frame_size - kNalHeaderSize; ++i) { + frame[i + kNalHeaderSize] = i; + } + RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(1); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = frame_size; + std::unique_ptr<RtpPacketizer> packetizer( + CreateH264Packetizer(H264PacketizationMode::NonInterleaved, + max_payload_size, last_packet_reduction)); + EXPECT_EQ( + expected_sizes.size(), + packetizer->SetPayloadData(frame.get(), frame_size, &fragmentation)); + + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(max_payload_size, packet.FreeCapacity()); + size_t offset = kNalHeaderSize; + for (size_t i = 0; i < expected_sizes.size(); ++i) { + ASSERT_TRUE(packetizer->NextPacket(&packet)); + VerifyFua(i, frame.get(), offset, packet.payload(), expected_sizes); + offset += expected_sizes[i]; + } + + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +size_t GetExpectedNaluOffset(const RTPFragmentationHeader& fragmentation, + size_t start_index, + size_t nalu_index) { + assert(nalu_index < fragmentation.fragmentationVectorSize); + size_t expected_nalu_offset = kNalHeaderSize; // STAP-A header. + for (size_t i = start_index; i < nalu_index; ++i) { + expected_nalu_offset += + kLengthFieldLength + fragmentation.fragmentationLength[i]; + } + return expected_nalu_offset; +} + +void VerifyStapAPayload(const RTPFragmentationHeader& fragmentation, + size_t first_stapa_index, + size_t nalu_index, + rtc::ArrayView<const uint8_t> frame, + rtc::ArrayView<const uint8_t> packet) { + size_t expected_payload_offset = + GetExpectedNaluOffset(fragmentation, first_stapa_index, nalu_index) + + kLengthFieldLength; + size_t offset = fragmentation.fragmentationOffset[nalu_index]; + const uint8_t* expected_payload = &frame[offset]; + size_t expected_payload_length = + fragmentation.fragmentationLength[nalu_index]; + ASSERT_LE(offset + expected_payload_length, frame.size()); + ASSERT_LE(expected_payload_offset + expected_payload_length, packet.size()); + std::vector<uint8_t> expected_payload_vector( + expected_payload, &expected_payload[expected_payload_length]); + EXPECT_THAT(expected_payload_vector, + ElementsAreArray(&packet[expected_payload_offset], + expected_payload_length)); +} + +void VerifySingleNaluPayload(const RTPFragmentationHeader& fragmentation, + size_t nalu_index, + rtc::ArrayView<const uint8_t> frame, + rtc::ArrayView<const uint8_t> packet) { + auto fragment = frame.subview(fragmentation.fragmentationOffset[nalu_index], + fragmentation.fragmentationLength[nalu_index]); + EXPECT_THAT(packet, ElementsAreArray(fragment.begin(), fragment.end())); +} +} // namespace + +// Tests that should work with both packetization mode 0 and +// packetization mode 1. +class RtpPacketizerH264ModeTest + : public ::testing::TestWithParam<H264PacketizationMode> {}; + +TEST_P(RtpPacketizerH264ModeTest, TestSingleNalu) { + const uint8_t frame[2] = {0x05, 0xFF}; // F=0, NRI=0, Type=5. + RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(1); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = sizeof(frame); + std::unique_ptr<RtpPacketizer> packetizer( + CreateH264Packetizer(GetParam(), kMaxPayloadSize, 0)); + ASSERT_EQ(1u, + packetizer->SetPayloadData(frame, sizeof(frame), &fragmentation)); + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); + ASSERT_TRUE(packetizer->NextPacket(&packet)); + EXPECT_EQ(2u, packet.payload_size()); + VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload()); + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +TEST_P(RtpPacketizerH264ModeTest, TestSingleNaluTwoPackets) { + const size_t kFrameSize = kMaxPayloadSize + 100; + uint8_t frame[kFrameSize] = {0}; + for (size_t i = 0; i < kFrameSize; ++i) + frame[i] = i; + RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(2); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = kMaxPayloadSize; + fragmentation.fragmentationOffset[1] = kMaxPayloadSize; + fragmentation.fragmentationLength[1] = 100; + // Set NAL headers. + frame[fragmentation.fragmentationOffset[0]] = 0x01; + frame[fragmentation.fragmentationOffset[1]] = 0x01; + + std::unique_ptr<RtpPacketizer> packetizer( + CreateH264Packetizer(GetParam(), kMaxPayloadSize, 0)); + ASSERT_EQ(2u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation)); + + RtpPacketToSend packet(kNoExtensions); + ASSERT_TRUE(packetizer->NextPacket(&packet)); + ASSERT_EQ(fragmentation.fragmentationOffset[1], packet.payload_size()); + VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload()); + + ASSERT_TRUE(packetizer->NextPacket(&packet)); + ASSERT_EQ(fragmentation.fragmentationLength[1], packet.payload_size()); + VerifySingleNaluPayload(fragmentation, 1, frame, packet.payload()); + + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +INSTANTIATE_TEST_CASE_P( + PacketMode, + RtpPacketizerH264ModeTest, + ::testing::Values(H264PacketizationMode::SingleNalUnit, + H264PacketizationMode::NonInterleaved)); + +TEST(RtpPacketizerH264Test, TestStapA) { + const size_t kFrameSize = + kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize; + uint8_t frame[kFrameSize] = {0x07, 0xFF, // F=0, NRI=0, Type=7 (SPS). + 0x08, 0xFF, // F=0, NRI=0, Type=8 (PPS). + 0x05}; // F=0, NRI=0, Type=5 (IDR). + const size_t kPayloadOffset = 5; + for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i) + frame[i + kPayloadOffset] = i; + RTPFragmentationHeader fragmentation; + CreateThreeFragments(&fragmentation, kFrameSize, kPayloadOffset); + std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer( + H264PacketizationMode::NonInterleaved, kMaxPayloadSize, 0)); + ASSERT_EQ(1u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation)); + + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); + ASSERT_TRUE(packetizer->NextPacket(&packet)); + size_t expected_packet_size = + kNalHeaderSize + 3 * kLengthFieldLength + kFrameSize; + ASSERT_EQ(expected_packet_size, packet.payload_size()); + + for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i) + VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload()); + + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +TEST(RtpPacketizerH264Test, TestStapARespectsPacketReduction) { + const size_t kLastPacketReduction = 100; + const size_t kFrameSize = kMaxPayloadSize - 1 - kLastPacketReduction; + uint8_t frame[kFrameSize] = {0x07, 0xFF, // F=0, NRI=0, Type=7. + 0x08, 0xFF, // F=0, NRI=0, Type=8. + 0x05}; // F=0, NRI=0, Type=5. + const size_t kPayloadOffset = 5; + for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i) + frame[i + kPayloadOffset] = i; + RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(3); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = 2; + fragmentation.fragmentationOffset[1] = 2; + fragmentation.fragmentationLength[1] = 2; + fragmentation.fragmentationOffset[2] = 4; + fragmentation.fragmentationLength[2] = + kNalHeaderSize + kFrameSize - kPayloadOffset; + std::unique_ptr<RtpPacketizer> packetizer( + CreateH264Packetizer(H264PacketizationMode::NonInterleaved, + kMaxPayloadSize, kLastPacketReduction)); + ASSERT_EQ(2u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation)); + + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); + ASSERT_TRUE(packetizer->NextPacket(&packet)); + size_t expected_packet_size = kNalHeaderSize; + for (size_t i = 0; i < 2; ++i) { + expected_packet_size += + kLengthFieldLength + fragmentation.fragmentationLength[i]; + } + ASSERT_EQ(expected_packet_size, packet.payload_size()); + for (size_t i = 0; i < 2; ++i) + VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload()); + + ASSERT_TRUE(packetizer->NextPacket(&packet)); + expected_packet_size = fragmentation.fragmentationLength[2]; + ASSERT_EQ(expected_packet_size, packet.payload_size()); + VerifySingleNaluPayload(fragmentation, 2, frame, packet.payload()); + + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +TEST(RtpPacketizerH264Test, TestSingleNalUnitModeHasNoStapA) { + // This is the same setup as for the TestStapA test. + const size_t kFrameSize = + kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize; + uint8_t frame[kFrameSize] = {0x07, 0xFF, // F=0, NRI=0, Type=7 (SPS). + 0x08, 0xFF, // F=0, NRI=0, Type=8 (PPS). + 0x05}; // F=0, NRI=0, Type=5 (IDR). + const size_t kPayloadOffset = 5; + for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i) + frame[i + kPayloadOffset] = i; + RTPFragmentationHeader fragmentation; + CreateThreeFragments(&fragmentation, kFrameSize, kPayloadOffset); + std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer( + H264PacketizationMode::SingleNalUnit, kMaxPayloadSize, 0)); + packetizer->SetPayloadData(frame, kFrameSize, &fragmentation); + + RtpPacketToSend packet(kNoExtensions); + // The three fragments should be returned as three packets. + ASSERT_TRUE(packetizer->NextPacket(&packet)); + ASSERT_TRUE(packetizer->NextPacket(&packet)); + ASSERT_TRUE(packetizer->NextPacket(&packet)); + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) { + const size_t kFrameSize = kMaxPayloadSize - 1; + uint8_t frame[kFrameSize] = {0x07, 0xFF, // F=0, NRI=0, Type=7. + 0x08, 0xFF, // F=0, NRI=0, Type=8. + 0x05}; // F=0, NRI=0, Type=5. + const size_t kPayloadOffset = 5; + for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i) + frame[i + kPayloadOffset] = i; + RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(3); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = 2; + fragmentation.fragmentationOffset[1] = 2; + fragmentation.fragmentationLength[1] = 2; + fragmentation.fragmentationOffset[2] = 4; + fragmentation.fragmentationLength[2] = + kNalHeaderSize + kFrameSize - kPayloadOffset; + std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer( + H264PacketizationMode::NonInterleaved, kMaxPayloadSize, 0)); + ASSERT_EQ(2u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation)); + + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); + ASSERT_TRUE(packetizer->NextPacket(&packet)); + size_t expected_packet_size = kNalHeaderSize; + for (size_t i = 0; i < 2; ++i) { + expected_packet_size += + kLengthFieldLength + fragmentation.fragmentationLength[i]; + } + ASSERT_EQ(expected_packet_size, packet.payload_size()); + for (size_t i = 0; i < 2; ++i) + VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload()); + + ASSERT_TRUE(packetizer->NextPacket(&packet)); + expected_packet_size = fragmentation.fragmentationLength[2]; + ASSERT_EQ(expected_packet_size, packet.payload_size()); + VerifySingleNaluPayload(fragmentation, 2, frame, packet.payload()); + + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +TEST(RtpPacketizerH264Test, TestMixedStapA_FUA) { + const size_t kFuaNaluSize = 2 * (kMaxPayloadSize - 100); + const size_t kStapANaluSize = 100; + RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(3); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = kFuaNaluSize; + fragmentation.fragmentationOffset[1] = kFuaNaluSize; + fragmentation.fragmentationLength[1] = kStapANaluSize; + fragmentation.fragmentationOffset[2] = kFuaNaluSize + kStapANaluSize; + fragmentation.fragmentationLength[2] = kStapANaluSize; + const size_t kFrameSize = kFuaNaluSize + 2 * kStapANaluSize; + uint8_t frame[kFrameSize]; + size_t nalu_offset = 0; + for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i) { + nalu_offset = fragmentation.fragmentationOffset[i]; + frame[nalu_offset] = 0x05; // F=0, NRI=0, Type=5. + for (size_t j = 1; j < fragmentation.fragmentationLength[i]; ++j) { + frame[nalu_offset + j] = i + j; + } + } + std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer( + H264PacketizationMode::NonInterleaved, kMaxPayloadSize, 0)); + ASSERT_EQ(3u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation)); + + // First expecting two FU-A packets. + std::vector<size_t> fua_sizes; + fua_sizes.push_back(1099); + fua_sizes.push_back(1100); + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity()); + int fua_offset = kNalHeaderSize; + for (size_t i = 0; i < 2; ++i) { + ASSERT_TRUE(packetizer->NextPacket(&packet)); + VerifyFua(i, frame, fua_offset, packet.payload(), fua_sizes); + fua_offset += fua_sizes[i]; + } + // Then expecting one STAP-A packet with two nal units. + ASSERT_TRUE(packetizer->NextPacket(&packet)); + size_t expected_packet_size = + kNalHeaderSize + 2 * kLengthFieldLength + 2 * kStapANaluSize; + ASSERT_EQ(expected_packet_size, packet.payload_size()); + for (size_t i = 1; i < fragmentation.fragmentationVectorSize; ++i) + VerifyStapAPayload(fragmentation, 1, i, frame, packet.payload()); + + EXPECT_FALSE(packetizer->NextPacket(&packet)); +} + +TEST(RtpPacketizerH264Test, TestFUAOddSize) { + const size_t kExpectedPayloadSizes[2] = {600, 600}; + TestFua( + kMaxPayloadSize + 1, kMaxPayloadSize, 0, + std::vector<size_t>(kExpectedPayloadSizes, + kExpectedPayloadSizes + + sizeof(kExpectedPayloadSizes) / sizeof(size_t))); +} + +TEST(RtpPacketizerH264Test, TestFUAWithLastPacketReduction) { + const size_t kExpectedPayloadSizes[2] = {601, 597}; + TestFua( + kMaxPayloadSize - 1, kMaxPayloadSize, 4, + std::vector<size_t>(kExpectedPayloadSizes, + kExpectedPayloadSizes + + sizeof(kExpectedPayloadSizes) / sizeof(size_t))); +} + +TEST(RtpPacketizerH264Test, TestFUAEvenSize) { + const size_t kExpectedPayloadSizes[2] = {600, 601}; + TestFua( + kMaxPayloadSize + 2, kMaxPayloadSize, 0, + std::vector<size_t>(kExpectedPayloadSizes, + kExpectedPayloadSizes + + sizeof(kExpectedPayloadSizes) / sizeof(size_t))); +} + +TEST(RtpPacketizerH264Test, TestFUARounding) { + const size_t kExpectedPayloadSizes[8] = {1265, 1265, 1265, 1265, + 1265, 1266, 1266, 1266}; + TestFua( + 10124, 1448, 0, + std::vector<size_t>(kExpectedPayloadSizes, + kExpectedPayloadSizes + + sizeof(kExpectedPayloadSizes) / sizeof(size_t))); +} + +TEST(RtpPacketizerH264Test, TestFUABig) { + const size_t kExpectedPayloadSizes[10] = {1198, 1198, 1198, 1198, 1198, + 1198, 1198, 1198, 1198, 1198}; + // Generate 10 full sized packets, leave room for FU-A headers minus the NALU + // header. + TestFua( + 10 * (kMaxPayloadSize - kFuAHeaderSize) + kNalHeaderSize, kMaxPayloadSize, + 0, + std::vector<size_t>(kExpectedPayloadSizes, + kExpectedPayloadSizes + + sizeof(kExpectedPayloadSizes) / sizeof(size_t))); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +TEST(RtpPacketizerH264DeathTest, SendOverlongDataInPacketizationMode0) { + const size_t kFrameSize = kMaxPayloadSize + 1; + uint8_t frame[kFrameSize] = {0}; + for (size_t i = 0; i < kFrameSize; ++i) + frame[i] = i; + RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(1); + fragmentation.fragmentationOffset[0] = 0; + fragmentation.fragmentationLength[0] = kFrameSize; + // Set NAL headers. + frame[fragmentation.fragmentationOffset[0]] = 0x01; + + std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer( + H264PacketizationMode::SingleNalUnit, kMaxPayloadSize, 0)); + EXPECT_DEATH(packetizer->SetPayloadData(frame, kFrameSize, &fragmentation), + "payload_size"); +} + +#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +namespace { +const uint8_t kStartSequence[] = {0x00, 0x00, 0x00, 0x01}; +const uint8_t kOriginalSps[] = {kSps, 0x00, 0x00, 0x03, 0x03, + 0xF4, 0x05, 0x03, 0xC7, 0xC0}; +const uint8_t kRewrittenSps[] = {kSps, 0x00, 0x00, 0x03, 0x03, 0xF4, 0x05, 0x03, + 0xC7, 0xE0, 0x1B, 0x41, 0x10, 0x8D, 0x00}; +const uint8_t kIdrOne[] = {kIdr, 0xFF, 0x00, 0x00, 0x04}; +const uint8_t kIdrTwo[] = {kIdr, 0xFF, 0x00, 0x11}; +} + +class RtpPacketizerH264TestSpsRewriting : public ::testing::Test { + public: + void SetUp() override { + fragmentation_header_.VerifyAndAllocateFragmentationHeader(3); + fragmentation_header_.fragmentationVectorSize = 3; + in_buffer_.AppendData(kStartSequence); + + fragmentation_header_.fragmentationOffset[0] = in_buffer_.size(); + fragmentation_header_.fragmentationLength[0] = sizeof(kOriginalSps); + in_buffer_.AppendData(kOriginalSps); + + fragmentation_header_.fragmentationOffset[1] = in_buffer_.size(); + fragmentation_header_.fragmentationLength[1] = sizeof(kIdrOne); + in_buffer_.AppendData(kIdrOne); + + fragmentation_header_.fragmentationOffset[2] = in_buffer_.size(); + fragmentation_header_.fragmentationLength[2] = sizeof(kIdrTwo); + in_buffer_.AppendData(kIdrTwo); + } + + protected: + rtc::Buffer in_buffer_; + RTPFragmentationHeader fragmentation_header_; + std::unique_ptr<RtpPacketizer> packetizer_; +}; + +TEST_F(RtpPacketizerH264TestSpsRewriting, FuASps) { + const size_t kHeaderOverhead = kFuAHeaderSize + 1; + + // Set size to fragment SPS into two FU-A packets. + packetizer_.reset( + CreateH264Packetizer(H264PacketizationMode::NonInterleaved, + sizeof(kOriginalSps) - 2 + kHeaderOverhead, 0)); + + packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(), + &fragmentation_header_); + + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(sizeof(kOriginalSps) + kHeaderOverhead, packet.FreeCapacity()); + + EXPECT_TRUE(packetizer_->NextPacket(&packet)); + size_t offset = H264::kNaluTypeSize; + size_t length = packet.payload_size() - kFuAHeaderSize; + EXPECT_THAT(packet.payload().subview(kFuAHeaderSize), + ElementsAreArray(&kRewrittenSps[offset], length)); + offset += length; + + EXPECT_TRUE(packetizer_->NextPacket(&packet)); + length = packet.payload_size() - kFuAHeaderSize; + EXPECT_THAT(packet.payload().subview(kFuAHeaderSize), + ElementsAreArray(&kRewrittenSps[offset], length)); + offset += length; + + EXPECT_EQ(offset, sizeof(kRewrittenSps)); +} + +TEST_F(RtpPacketizerH264TestSpsRewriting, StapASps) { + const size_t kHeaderOverhead = kFuAHeaderSize + 1; + const size_t kExpectedTotalSize = H264::kNaluTypeSize + // Stap-A type. + sizeof(kRewrittenSps) + sizeof(kIdrOne) + + sizeof(kIdrTwo) + (kLengthFieldLength * 3); + + // Set size to include SPS and the rest of the packets in a Stap-A package. + packetizer_.reset(CreateH264Packetizer(H264PacketizationMode::NonInterleaved, + kExpectedTotalSize + kHeaderOverhead, + 0)); + + packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(), + &fragmentation_header_); + + RtpPacketToSend packet(kNoExtensions); + ASSERT_LE(kExpectedTotalSize + kHeaderOverhead, packet.FreeCapacity()); + + EXPECT_TRUE(packetizer_->NextPacket(&packet)); + EXPECT_EQ(kExpectedTotalSize, packet.payload_size()); + EXPECT_THAT(packet.payload().subview(H264::kNaluTypeSize + kLengthFieldLength, + sizeof(kRewrittenSps)), + ElementsAreArray(kRewrittenSps)); +} + +class RtpDepacketizerH264Test : public ::testing::Test { + protected: + RtpDepacketizerH264Test() + : depacketizer_(RtpDepacketizer::Create(kRtpVideoH264)) {} + + void ExpectPacket(RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* data, + size_t length) { + ASSERT_TRUE(parsed_payload != NULL); + EXPECT_THAT(std::vector<uint8_t>( + parsed_payload->payload, + parsed_payload->payload + parsed_payload->payload_length), + ::testing::ElementsAreArray(data, length)); + } + + std::unique_ptr<RtpDepacketizer> depacketizer_; +}; + +TEST_F(RtpDepacketizerH264Test, TestSingleNalu) { + uint8_t packet[2] = {0x05, 0xFF}; // F=0, NRI=0, Type=5 (IDR). + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame); + EXPECT_EQ(kH264SingleNalu, + payload.type.Video.codecHeader.H264.packetization_type); + EXPECT_EQ(kIdr, payload.type.Video.codecHeader.H264.nalu_type); +} + +TEST_F(RtpDepacketizerH264Test, TestSingleNaluSpsWithResolution) { + uint8_t packet[] = {kSps, 0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50, + 0x05, 0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, + 0x00, 0x00, 0x03, 0x2A, 0xE0, 0xF1, 0x83, 0x25}; + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame); + EXPECT_EQ(kH264SingleNalu, + payload.type.Video.codecHeader.H264.packetization_type); + EXPECT_EQ(1280u, payload.type.Video.width); + EXPECT_EQ(720u, payload.type.Video.height); +} + +TEST_F(RtpDepacketizerH264Test, TestStapAKey) { + // clang-format off + const NaluInfo kExpectedNalus[] = { {H264::kSps, 0, -1}, + {H264::kPps, 1, 2}, + {H264::kIdr, -1, 0} }; + uint8_t packet[] = {kStapA, // F=0, NRI=0, Type=24. + // Length, nal header, payload. + 0, 0x18, kExpectedNalus[0].type, + 0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50, 0x05, 0xBA, + 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x03, + 0x2A, 0xE0, 0xF1, 0x83, 0x25, + 0, 0xD, kExpectedNalus[1].type, + 0x69, 0xFC, 0x0, 0x0, 0x3, 0x0, 0x7, 0xFF, 0xFF, 0xFF, + 0xF6, 0x40, + 0, 0xB, kExpectedNalus[2].type, + 0x85, 0xB8, 0x0, 0x4, 0x0, 0x0, 0x13, 0x93, 0x12, 0x0}; + // clang-format on + + RtpDepacketizer::ParsedPayload payload; + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame); + const RTPVideoHeaderH264& h264 = payload.type.Video.codecHeader.H264; + EXPECT_EQ(kH264StapA, h264.packetization_type); + // NALU type for aggregated packets is the type of the first packet only. + EXPECT_EQ(kSps, h264.nalu_type); + ASSERT_EQ(3u, h264.nalus_length); + for (size_t i = 0; i < h264.nalus_length; ++i) { + EXPECT_EQ(kExpectedNalus[i].type, h264.nalus[i].type) + << "Failed parsing nalu " << i; + EXPECT_EQ(kExpectedNalus[i].sps_id, h264.nalus[i].sps_id) + << "Failed parsing nalu " << i; + EXPECT_EQ(kExpectedNalus[i].pps_id, h264.nalus[i].pps_id) + << "Failed parsing nalu " << i; + } +} + +TEST_F(RtpDepacketizerH264Test, TestStapANaluSpsWithResolution) { + uint8_t packet[] = {kStapA, // F=0, NRI=0, Type=24. + // Length (2 bytes), nal header, payload. + 0x00, 0x19, kSps, 0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, + 0x50, 0x05, 0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, + 0x00, 0x00, 0x03, 0x2A, 0xE0, 0xF1, 0x83, 0x25, 0x80, + 0x00, 0x03, kIdr, 0xFF, 0x00, 0x00, 0x04, kIdr, 0xFF, + 0x00, 0x11}; + + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame); + EXPECT_EQ(kH264StapA, payload.type.Video.codecHeader.H264.packetization_type); + EXPECT_EQ(1280u, payload.type.Video.width); + EXPECT_EQ(720u, payload.type.Video.height); +} + +TEST_F(RtpDepacketizerH264Test, TestEmptyStapARejected) { + uint8_t lone_empty_packet[] = {kStapA, 0x00, 0x00}; + + uint8_t leading_empty_packet[] = {kStapA, 0x00, 0x00, 0x00, 0x04, + kIdr, 0xFF, 0x00, 0x11}; + + uint8_t middle_empty_packet[] = {kStapA, 0x00, 0x03, kIdr, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x04, kIdr, 0xFF, 0x00, 0x11}; + + uint8_t trailing_empty_packet[] = {kStapA, 0x00, 0x03, kIdr, + 0xFF, 0x00, 0x00, 0x00}; + + RtpDepacketizer::ParsedPayload payload; + + EXPECT_FALSE(depacketizer_->Parse(&payload, lone_empty_packet, + sizeof(lone_empty_packet))); + EXPECT_FALSE(depacketizer_->Parse(&payload, leading_empty_packet, + sizeof(leading_empty_packet))); + EXPECT_FALSE(depacketizer_->Parse(&payload, middle_empty_packet, + sizeof(middle_empty_packet))); + EXPECT_FALSE(depacketizer_->Parse(&payload, trailing_empty_packet, + sizeof(trailing_empty_packet))); +} + +TEST_F(RtpDepacketizerH264Test, DepacketizeWithRewriting) { + rtc::Buffer in_buffer; + rtc::Buffer out_buffer; + + uint8_t kHeader[2] = {kStapA}; + in_buffer.AppendData(kHeader, 1); + out_buffer.AppendData(kHeader, 1); + + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps)); + in_buffer.AppendData(kHeader, 2); + in_buffer.AppendData(kOriginalSps); + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kRewrittenSps)); + out_buffer.AppendData(kHeader, 2); + out_buffer.AppendData(kRewrittenSps); + + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrOne)); + in_buffer.AppendData(kHeader, 2); + in_buffer.AppendData(kIdrOne); + out_buffer.AppendData(kHeader, 2); + out_buffer.AppendData(kIdrOne); + + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrTwo)); + in_buffer.AppendData(kHeader, 2); + in_buffer.AppendData(kIdrTwo); + out_buffer.AppendData(kHeader, 2); + out_buffer.AppendData(kIdrTwo); + + RtpDepacketizer::ParsedPayload payload; + EXPECT_TRUE( + depacketizer_->Parse(&payload, in_buffer.data(), in_buffer.size())); + + std::vector<uint8_t> expected_packet_payload( + out_buffer.data(), &out_buffer.data()[out_buffer.size()]); + + EXPECT_THAT( + expected_packet_payload, + ::testing::ElementsAreArray(payload.payload, payload.payload_length)); +} + +TEST_F(RtpDepacketizerH264Test, DepacketizeWithDoubleRewriting) { + rtc::Buffer in_buffer; + rtc::Buffer out_buffer; + + uint8_t kHeader[2] = {kStapA}; + in_buffer.AppendData(kHeader, 1); + out_buffer.AppendData(kHeader, 1); + + // First SPS will be kept... + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps)); + in_buffer.AppendData(kHeader, 2); + in_buffer.AppendData(kOriginalSps); + out_buffer.AppendData(kHeader, 2); + out_buffer.AppendData(kOriginalSps); + + // ...only the second one will be rewritten. + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps)); + in_buffer.AppendData(kHeader, 2); + in_buffer.AppendData(kOriginalSps); + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kRewrittenSps)); + out_buffer.AppendData(kHeader, 2); + out_buffer.AppendData(kRewrittenSps); + + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrOne)); + in_buffer.AppendData(kHeader, 2); + in_buffer.AppendData(kIdrOne); + out_buffer.AppendData(kHeader, 2); + out_buffer.AppendData(kIdrOne); + + ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrTwo)); + in_buffer.AppendData(kHeader, 2); + in_buffer.AppendData(kIdrTwo); + out_buffer.AppendData(kHeader, 2); + out_buffer.AppendData(kIdrTwo); + + RtpDepacketizer::ParsedPayload payload; + EXPECT_TRUE( + depacketizer_->Parse(&payload, in_buffer.data(), in_buffer.size())); + + std::vector<uint8_t> expected_packet_payload( + out_buffer.data(), &out_buffer.data()[out_buffer.size()]); + + EXPECT_THAT( + expected_packet_payload, + ::testing::ElementsAreArray(payload.payload, payload.payload_length)); +} + +TEST_F(RtpDepacketizerH264Test, TestStapADelta) { + uint8_t packet[16] = {kStapA, // F=0, NRI=0, Type=24. + // Length, nal header, payload. + 0, 0x02, kSlice, 0xFF, 0, 0x03, kSlice, 0xFF, + 0x00, 0, 0x04, kSlice, 0xFF, 0x00, 0x11}; + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket(&payload, packet, sizeof(packet)); + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame); + EXPECT_EQ(kH264StapA, payload.type.Video.codecHeader.H264.packetization_type); + // NALU type for aggregated packets is the type of the first packet only. + EXPECT_EQ(kSlice, payload.type.Video.codecHeader.H264.nalu_type); +} + +TEST_F(RtpDepacketizerH264Test, TestFuA) { + // clang-format off + uint8_t packet1[] = { + kFuA, // F=0, NRI=0, Type=28. + kSBit | kIdr, // FU header. + 0x85, 0xB8, 0x0, 0x4, 0x0, 0x0, 0x13, 0x93, 0x12, 0x0 // Payload. + }; + // clang-format on + const uint8_t kExpected1[] = {kIdr, 0x85, 0xB8, 0x0, 0x4, 0x0, + 0x0, 0x13, 0x93, 0x12, 0x0}; + + uint8_t packet2[] = { + kFuA, // F=0, NRI=0, Type=28. + kIdr, // FU header. + 0x02 // Payload. + }; + const uint8_t kExpected2[] = {0x02}; + + uint8_t packet3[] = { + kFuA, // F=0, NRI=0, Type=28. + kEBit | kIdr, // FU header. + 0x03 // Payload. + }; + const uint8_t kExpected3[] = {0x03}; + + RtpDepacketizer::ParsedPayload payload; + + // We expect that the first packet is one byte shorter since the FU-A header + // has been replaced by the original nal header. + ASSERT_TRUE(depacketizer_->Parse(&payload, packet1, sizeof(packet1))); + ExpectPacket(&payload, kExpected1, sizeof(kExpected1)); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_TRUE(payload.type.Video.is_first_packet_in_frame); + const RTPVideoHeaderH264& h264 = payload.type.Video.codecHeader.H264; + EXPECT_EQ(kH264FuA, h264.packetization_type); + EXPECT_EQ(kIdr, h264.nalu_type); + ASSERT_EQ(1u, h264.nalus_length); + EXPECT_EQ(static_cast<H264::NaluType>(kIdr), h264.nalus[0].type); + EXPECT_EQ(-1, h264.nalus[0].sps_id); + EXPECT_EQ(0, h264.nalus[0].pps_id); + + // Following packets will be 2 bytes shorter since they will only be appended + // onto the first packet. + payload = RtpDepacketizer::ParsedPayload(); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet2, sizeof(packet2))); + ExpectPacket(&payload, kExpected2, sizeof(kExpected2)); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_FALSE(payload.type.Video.is_first_packet_in_frame); + { + const RTPVideoHeaderH264& h264 = payload.type.Video.codecHeader.H264; + EXPECT_EQ(kH264FuA, h264.packetization_type); + EXPECT_EQ(kIdr, h264.nalu_type); + // NALU info is only expected for the first FU-A packet. + EXPECT_EQ(0u, h264.nalus_length); + } + + payload = RtpDepacketizer::ParsedPayload(); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet3, sizeof(packet3))); + ExpectPacket(&payload, kExpected3, sizeof(kExpected3)); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoH264, payload.type.Video.codec); + EXPECT_FALSE(payload.type.Video.is_first_packet_in_frame); + { + const RTPVideoHeaderH264& h264 = payload.type.Video.codecHeader.H264; + EXPECT_EQ(kH264FuA, h264.packetization_type); + EXPECT_EQ(kIdr, h264.nalu_type); + // NALU info is only expected for the first FU-A packet. + ASSERT_EQ(0u, h264.nalus_length); + } +} + +TEST_F(RtpDepacketizerH264Test, TestEmptyPayload) { + // Using a wild pointer to crash on accesses from inside the depacketizer. + uint8_t* garbage_ptr = reinterpret_cast<uint8_t*>(0x4711); + RtpDepacketizer::ParsedPayload payload; + EXPECT_FALSE(depacketizer_->Parse(&payload, garbage_ptr, 0)); +} + +TEST_F(RtpDepacketizerH264Test, TestTruncatedFuaNalu) { + const uint8_t kPayload[] = {0x9c}; + RtpDepacketizer::ParsedPayload payload; + EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload))); +} + +TEST_F(RtpDepacketizerH264Test, TestTruncatedSingleStapANalu) { + const uint8_t kPayload[] = {0xd8, 0x27}; + RtpDepacketizer::ParsedPayload payload; + EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload))); +} + +TEST_F(RtpDepacketizerH264Test, TestStapAPacketWithTruncatedNalUnits) { + const uint8_t kPayload[] = { 0x58, 0xCB, 0xED, 0xDF}; + RtpDepacketizer::ParsedPayload payload; + EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload))); +} + +TEST_F(RtpDepacketizerH264Test, TestTruncationJustAfterSingleStapANalu) { + const uint8_t kPayload[] = {0x38, 0x27, 0x27}; + RtpDepacketizer::ParsedPayload payload; + EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload))); +} + +TEST_F(RtpDepacketizerH264Test, TestShortSpsPacket) { + const uint8_t kPayload[] = {0x27, 0x80, 0x00}; + RtpDepacketizer::ParsedPayload payload; + EXPECT_TRUE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload))); +} + +TEST_F(RtpDepacketizerH264Test, TestSeiPacket) { + const uint8_t kPayload[] = { + kSei, // F=0, NRI=0, Type=6. + 0x03, 0x03, 0x03, 0x03 // Payload. + }; + RtpDepacketizer::ParsedPayload payload; + ASSERT_TRUE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload))); + const RTPVideoHeaderH264& h264 = payload.type.Video.codecHeader.H264; + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); + EXPECT_EQ(kH264SingleNalu, h264.packetization_type); + EXPECT_EQ(kSei, h264.nalu_type); + ASSERT_EQ(1u, h264.nalus_length); + EXPECT_EQ(static_cast<H264::NaluType>(kSei), h264.nalus[0].type); + EXPECT_EQ(-1, h264.nalus[0].sps_id); + EXPECT_EQ(-1, h264.nalus[0].pps_id); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc new file mode 100644 index 0000000000..0c9bb439e0 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc @@ -0,0 +1,141 @@ +/* + * 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 <string> + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/rtp_format_video_generic.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +static const size_t kGenericHeaderLength = 1; + +RtpPacketizerGeneric::RtpPacketizerGeneric(FrameType frame_type, + size_t max_payload_len, + size_t last_packet_reduction_len) + : payload_data_(NULL), + payload_size_(0), + max_payload_len_(max_payload_len - kGenericHeaderLength), + last_packet_reduction_len_(last_packet_reduction_len), + frame_type_(frame_type), + num_packets_left_(0), + num_larger_packets_(0) {} + +RtpPacketizerGeneric::~RtpPacketizerGeneric() { +} + +size_t RtpPacketizerGeneric::SetPayloadData( + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) { + payload_data_ = payload_data; + payload_size_ = payload_size; + + // Fragment packets such that they are almost the same size, even accounting + // for larger header in the last packet. + // Since we are given how much extra space is occupied by the longer header + // in the last packet, we can pretend that RTP headers are the same, but + // there's last_packet_reduction_len_ virtual payload, to be put at the end of + // the last packet. + // + size_t total_bytes = payload_size_ + last_packet_reduction_len_; + + // Minimum needed number of packets to fit payload and virtual payload in the + // last packet. + num_packets_left_ = (total_bytes + max_payload_len_ - 1) / max_payload_len_; + // Given number of packets, calculate average size rounded down. + payload_len_per_packet_ = total_bytes / num_packets_left_; + // If we can't divide everything perfectly evenly, we put 1 extra byte in some + // last packets: 14 bytes in 4 packets would be split as 3+3+4+4. + num_larger_packets_ = total_bytes % num_packets_left_; + RTC_DCHECK_LE(payload_len_per_packet_, max_payload_len_); + + generic_header_ = RtpFormatVideoGeneric::kFirstPacketBit; + if (frame_type_ == kVideoFrameKey) { + generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit; + } + return num_packets_left_; +} + +bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet) { + RTC_DCHECK(packet); + if (num_packets_left_ == 0) + return false; + // Last larger_packets_ packets are 1 byte larger than previous packets. + // Increase per packet payload once needed. + if (num_packets_left_ == num_larger_packets_) + ++payload_len_per_packet_; + size_t next_packet_payload_len = payload_len_per_packet_; + if (payload_size_ <= next_packet_payload_len) { + // Whole payload fits into this packet. + next_packet_payload_len = payload_size_; + if (num_packets_left_ == 2) { + // This is the penultimate packet. Leave at least 1 payload byte for the + // last packet. + --next_packet_payload_len; + RTC_DCHECK_GT(next_packet_payload_len, 0); + } + } + RTC_DCHECK_LE(next_packet_payload_len, max_payload_len_); + + uint8_t* out_ptr = + packet->AllocatePayload(kGenericHeaderLength + next_packet_payload_len); + // Put generic header in packet. + out_ptr[0] = generic_header_; + // Remove first-packet bit, following packets are intermediate. + generic_header_ &= ~RtpFormatVideoGeneric::kFirstPacketBit; + + // Put payload in packet. + memcpy(out_ptr + kGenericHeaderLength, payload_data_, + next_packet_payload_len); + payload_data_ += next_packet_payload_len; + payload_size_ -= next_packet_payload_len; + --num_packets_left_; + // Packets left to produce and data left to split should end at the same time. + RTC_DCHECK_EQ(num_packets_left_ == 0, payload_size_ == 0); + + packet->SetMarker(payload_size_ == 0); + + return true; +} + +std::string RtpPacketizerGeneric::ToString() { + return "RtpPacketizerGeneric"; +} + +bool RtpDepacketizerGeneric::Parse(ParsedPayload* parsed_payload, + const uint8_t* payload_data, + size_t payload_data_length) { + assert(parsed_payload != NULL); + if (payload_data_length == 0) { + RTC_LOG(LS_ERROR) << "Empty payload."; + return false; + } + + uint8_t generic_header = *payload_data++; + --payload_data_length; + + parsed_payload->frame_type = + ((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0) + ? kVideoFrameKey + : kVideoFrameDelta; + parsed_payload->type.Video.is_first_packet_in_frame = + (generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0; + parsed_payload->type.Video.codec = kRtpVideoGeneric; + parsed_payload->type.Video.width = 0; + parsed_payload->type.Video.height = 0; + + parsed_payload->payload = payload_data; + parsed_payload->payload_length = payload_data_length; + return true; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h new file mode 100644 index 0000000000..a9da5da1d5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h @@ -0,0 +1,74 @@ +/* + * 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. + */ +#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_ + +#include <string> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "rtc_base/constructormagic.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace RtpFormatVideoGeneric { +static const uint8_t kKeyFrameBit = 0x01; +static const uint8_t kFirstPacketBit = 0x02; +} // namespace RtpFormatVideoGeneric + +class RtpPacketizerGeneric : public RtpPacketizer { + public: + // Initialize with payload from encoder. + // The payload_data must be exactly one encoded generic frame. + RtpPacketizerGeneric(FrameType frametype, + size_t max_payload_len, + size_t last_packet_reduction_len); + + virtual ~RtpPacketizerGeneric(); + + // Returns total number of packets to be generated. + size_t SetPayloadData(const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) override; + + // Get the next payload with generic payload header. + // Write payload and set marker bit of the |packet|. + // Returns true on success, false otherwise. + bool NextPacket(RtpPacketToSend* packet) override; + + std::string ToString() override; + + private: + const uint8_t* payload_data_; + size_t payload_size_; + const size_t max_payload_len_; + const size_t last_packet_reduction_len_; + FrameType frame_type_; + size_t payload_len_per_packet_; + uint8_t generic_header_; + // Number of packets yet to be retrieved by NextPacket() call. + size_t num_packets_left_; + // Number of packets, which will be 1 byte more than the rest. + size_t num_larger_packets_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerGeneric); +}; + +// Depacketizer for generic codec. +class RtpDepacketizerGeneric : public RtpDepacketizer { + public: + virtual ~RtpDepacketizerGeneric() {} + + bool Parse(ParsedPayload* parsed_payload, + const uint8_t* payload_data, + size_t payload_data_length) override; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc new file mode 100644 index 0000000000..85d6689376 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2017 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 <algorithm> +#include <limits> +#include <memory> +#include <vector> + +#include "api/array_view.h" +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_format_video_generic.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::Each; +using ::testing::ElementsAreArray; +using ::testing::Le; +using ::testing::SizeIs; + +const size_t kMaxPayloadSize = 1200; + +uint8_t kTestPayload[kMaxPayloadSize]; + +std::vector<size_t> NextPacketFillPayloadSizes( + RtpPacketizerGeneric* packetizer) { + RtpPacketToSend packet(nullptr); + std::vector<size_t> result; + while (packetizer->NextPacket(&packet)) { + result.push_back(packet.payload_size()); + } + return result; +} + +size_t GetEffectivePacketsSizeDifference(std::vector<size_t>* payload_sizes, + size_t last_packet_reduction_len) { + // Account for larger last packet header. + payload_sizes->back() += last_packet_reduction_len; + auto minmax = + std::minmax_element(payload_sizes->begin(), payload_sizes->end()); + // MAX-MIN + size_t difference = *minmax.second - *minmax.first; + // Revert temporary changes. + payload_sizes->back() -= last_packet_reduction_len; + return difference; +} + +} // namespace + +TEST(RtpPacketizerVideoGeneric, AllPacketsMayBeEqual_RespectsMaxPayloadSize) { + const size_t kMaxPayloadLen = 6; + const size_t kLastPacketReductionLen = 2; + const size_t kPayloadSize = 13; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + EXPECT_THAT(payload_sizes, Each(Le(kMaxPayloadLen))); +} + +TEST(RtpPacketizerVideoGeneric, + AllPacketsMayBeEqual_RespectsLastPacketReductionLength) { + const size_t kMaxPayloadLen = 6; + const size_t kLastPacketReductionLen = 2; + const size_t kPayloadSize = 13; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + EXPECT_LE(payload_sizes.back(), kMaxPayloadLen - kLastPacketReductionLen); +} + +TEST(RtpPacketizerVideoGeneric, + AllPacketsMayBeEqual_MakesPacketsAlmostEqualInSize) { + const size_t kMaxPayloadLen = 6; + const size_t kLastPacketReductionLen = 2; + const size_t kPayloadSize = 13; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + size_t sizes_difference = GetEffectivePacketsSizeDifference( + &payload_sizes, kLastPacketReductionLen); + EXPECT_LE(sizes_difference, 1u); +} + +TEST(RtpPacketizerVideoGeneric, + AllPacketsMayBeEqual_GeneratesMinimumNumberOfPackets) { + const size_t kMaxPayloadLen = 6; + const size_t kLastPacketReductionLen = 3; + const size_t kPayloadSize = 13; + // Computed by hand. 3 packets would have capacity 3*(6-1)-3=12 (max length - + // generic header lengh for each packet minus last packet reduction). + // 4 packets is enough for kPayloadSize. + const size_t kMinNumPackets = 4; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + EXPECT_EQ(num_packets, kMinNumPackets); +} + +TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmaller_RespectsMaxPayloadSize) { + const size_t kMaxPayloadLen = 8; + const size_t kLastPacketReductionLen = 5; + const size_t kPayloadSize = 28; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + EXPECT_THAT(payload_sizes, Each(Le(kMaxPayloadLen))); +} + +TEST(RtpPacketizerVideoGeneric, + SomePacketsAreSmaller_RespectsLastPacketReductionLength) { + const size_t kMaxPayloadLen = 8; + const size_t kLastPacketReductionLen = 5; + const size_t kPayloadSize = 28; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + EXPECT_LE(payload_sizes.back(), kMaxPayloadLen - kLastPacketReductionLen); +} + +TEST(RtpPacketizerVideoGeneric, + SomePacketsAreSmaller_MakesPacketsAlmostEqualInSize) { + const size_t kMaxPayloadLen = 8; + const size_t kLastPacketReductionLen = 5; + const size_t kPayloadSize = 28; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + size_t sizes_difference = GetEffectivePacketsSizeDifference( + &payload_sizes, kLastPacketReductionLen); + EXPECT_LE(sizes_difference, 1u); +} + +TEST(RtpPacketizerVideoGeneric, + SomePacketsAreSmaller_GeneratesMinimumNumberOfPackets) { + const size_t kMaxPayloadLen = 8; + const size_t kLastPacketReductionLen = 5; + const size_t kPayloadSize = 28; + // Computed by hand. 4 packets would have capacity 4*(8-1)-5=23 (max length - + // generic header lengh for each packet minus last packet reduction). + // 5 packets is enough for kPayloadSize. + const size_t kMinNumPackets = 5; + RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen, + kLastPacketReductionLen); + size_t num_packets = + packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr); + std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer); + EXPECT_THAT(payload_sizes, SizeIs(num_packets)); + + EXPECT_EQ(num_packets, kMinNumPackets); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc new file mode 100644 index 0000000000..74d20c50b2 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2011 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/rtp_rtcp/source/rtp_format_vp8.h" + +#include <string.h> // memcpy + +#include <limits> +#include <utility> +#include <vector> + +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { +int ParseVP8PictureID(RTPVideoHeaderVP8* vp8, + const uint8_t** data, + size_t* data_length, + size_t* parsed_bytes) { + if (*data_length == 0) + return -1; + + vp8->pictureId = (**data & 0x7F); + if (**data & 0x80) { + (*data)++; + (*parsed_bytes)++; + if (--(*data_length) == 0) + return -1; + // PictureId is 15 bits + vp8->pictureId = (vp8->pictureId << 8) + **data; + } + (*data)++; + (*parsed_bytes)++; + (*data_length)--; + return 0; +} + +int ParseVP8Tl0PicIdx(RTPVideoHeaderVP8* vp8, + const uint8_t** data, + size_t* data_length, + size_t* parsed_bytes) { + if (*data_length == 0) + return -1; + + vp8->tl0PicIdx = **data; + (*data)++; + (*parsed_bytes)++; + (*data_length)--; + return 0; +} + +int ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8* vp8, + const uint8_t** data, + size_t* data_length, + size_t* parsed_bytes, + bool has_tid, + bool has_key_idx) { + if (*data_length == 0) + return -1; + + if (has_tid) { + vp8->temporalIdx = ((**data >> 6) & 0x03); + vp8->layerSync = (**data & 0x20) ? true : false; // Y bit + } + if (has_key_idx) { + vp8->keyIdx = (**data & 0x1F); + } + (*data)++; + (*parsed_bytes)++; + (*data_length)--; + return 0; +} + +int ParseVP8Extension(RTPVideoHeaderVP8* vp8, + const uint8_t* data, + size_t data_length) { + RTC_DCHECK_GT(data_length, 0); + size_t parsed_bytes = 0; + // Optional X field is present. + bool has_picture_id = (*data & 0x80) ? true : false; // I bit + bool has_tl0_pic_idx = (*data & 0x40) ? true : false; // L bit + bool has_tid = (*data & 0x20) ? true : false; // T bit + bool has_key_idx = (*data & 0x10) ? true : false; // K bit + + // Advance data and decrease remaining payload size. + data++; + parsed_bytes++; + data_length--; + + if (has_picture_id) { + if (ParseVP8PictureID(vp8, &data, &data_length, &parsed_bytes) != 0) { + return -1; + } + } + + if (has_tl0_pic_idx) { + if (ParseVP8Tl0PicIdx(vp8, &data, &data_length, &parsed_bytes) != 0) { + return -1; + } + } + + if (has_tid || has_key_idx) { + if (ParseVP8TIDAndKeyIdx( + vp8, &data, &data_length, &parsed_bytes, has_tid, has_key_idx) != + 0) { + return -1; + } + } + return static_cast<int>(parsed_bytes); +} + +int ParseVP8FrameSize(RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* data, + size_t data_length) { + if (parsed_payload->frame_type != kVideoFrameKey) { + // Included in payload header for I-frames. + return 0; + } + if (data_length < 10) { + // For an I-frame we should always have the uncompressed VP8 header + // in the beginning of the partition. + return -1; + } + parsed_payload->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF; + parsed_payload->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF; + return 0; +} + +bool ValidateHeader(const RTPVideoHeaderVP8& hdr_info) { + if (hdr_info.pictureId != kNoPictureId) { + RTC_DCHECK_GE(hdr_info.pictureId, 0); + RTC_DCHECK_LE(hdr_info.pictureId, 0x7FFF); + } + if (hdr_info.tl0PicIdx != kNoTl0PicIdx) { + RTC_DCHECK_GE(hdr_info.tl0PicIdx, 0); + RTC_DCHECK_LE(hdr_info.tl0PicIdx, 0xFF); + } + if (hdr_info.temporalIdx != kNoTemporalIdx) { + RTC_DCHECK_GE(hdr_info.temporalIdx, 0); + RTC_DCHECK_LE(hdr_info.temporalIdx, 3); + } else { + RTC_DCHECK(!hdr_info.layerSync); + } + if (hdr_info.keyIdx != kNoKeyIdx) { + RTC_DCHECK_GE(hdr_info.keyIdx, 0); + RTC_DCHECK_LE(hdr_info.keyIdx, 0x1F); + } + return true; +} + +} // namespace + +RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, + size_t max_payload_len, + size_t last_packet_reduction_len) + : payload_data_(NULL), + payload_size_(0), + vp8_fixed_payload_descriptor_bytes_(1), + hdr_info_(hdr_info), + max_payload_len_(max_payload_len), + last_packet_reduction_len_(last_packet_reduction_len) { + RTC_DCHECK(ValidateHeader(hdr_info)); +} + +RtpPacketizerVp8::~RtpPacketizerVp8() { +} + +size_t RtpPacketizerVp8::SetPayloadData( + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* /* fragmentation */) { + payload_data_ = payload_data; + payload_size_ = payload_size; + if (GeneratePackets() < 0) { + return 0; + } + return packets_.size(); +} + +bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) { + RTC_DCHECK(packet); + if (packets_.empty()) { + return false; + } + InfoStruct packet_info = packets_.front(); + packets_.pop(); + + uint8_t* buffer = packet->AllocatePayload( + packets_.empty() ? max_payload_len_ - last_packet_reduction_len_ + : max_payload_len_); + int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_); + if (bytes < 0) { + return false; + } + packet->SetPayloadSize(bytes); + packet->SetMarker(packets_.empty()); + return true; +} + +std::string RtpPacketizerVp8::ToString() { + return "RtpPacketizerVp8"; +} + +int RtpPacketizerVp8::GeneratePackets() { + if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ + + PayloadDescriptorExtraLength() + 1 + + last_packet_reduction_len_) { + // The provided payload length is not long enough for the payload + // descriptor and one payload byte in the last packet. + // Return an error. + return -1; + } + + size_t per_packet_capacity = + max_payload_len_ - + (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength()); + + GeneratePacketsSplitPayloadBalanced(payload_size_, per_packet_capacity); + return 0; +} + +void RtpPacketizerVp8::GeneratePacketsSplitPayloadBalanced(size_t payload_len, + size_t capacity) { + // Last packet of the last partition is smaller. Pretend that it's the same + // size, but we must write more payload to it. + size_t total_bytes = payload_len + last_packet_reduction_len_; + // Integer divisions with rounding up. + size_t num_packets_left = (total_bytes + capacity - 1) / capacity; + size_t bytes_per_packet = total_bytes / num_packets_left; + size_t num_larger_packets = total_bytes % num_packets_left; + size_t remaining_data = payload_len; + while (remaining_data > 0) { + // Last num_larger_packets are 1 byte wider than the rest. Increase + // per-packet payload size when needed. + if (num_packets_left == num_larger_packets) + ++bytes_per_packet; + size_t current_packet_bytes = bytes_per_packet; + if (current_packet_bytes > remaining_data) { + current_packet_bytes = remaining_data; + } + // This is not the last packet in the whole payload, but there's no data + // left for the last packet. Leave at least one byte for the last packet. + if (num_packets_left == 2 && current_packet_bytes == remaining_data) { + --current_packet_bytes; + } + QueuePacket(payload_len - remaining_data, + current_packet_bytes, remaining_data == payload_len); + remaining_data -= current_packet_bytes; + --num_packets_left; + } +} + +void RtpPacketizerVp8::QueuePacket(size_t start_pos, + size_t packet_size, + bool first_packet) { + // Write info to packet info struct and store in packet info queue. + InfoStruct packet_info; + packet_info.payload_start_pos = start_pos; + packet_info.size = packet_size; + packet_info.first_packet = first_packet; + packets_.push(packet_info); +} + +int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info, + uint8_t* buffer, + size_t buffer_length) const { + // Write the VP8 payload descriptor. + // 0 + // 0 1 2 3 4 5 6 7 8 + // +-+-+-+-+-+-+-+-+-+ + // |X| |N|S| PART_ID | + // +-+-+-+-+-+-+-+-+-+ + // X: |I|L|T|K| | (mandatory if any of the below are used) + // +-+-+-+-+-+-+-+-+-+ + // I: |PictureID (8/16b)| (optional) + // +-+-+-+-+-+-+-+-+-+ + // L: | TL0PIC_IDX | (optional) + // +-+-+-+-+-+-+-+-+-+ + // T/K: |TID:Y| KEYIDX | (optional) + // +-+-+-+-+-+-+-+-+-+ + + RTC_DCHECK_GT(packet_info.size, 0); + buffer[0] = 0; + if (XFieldPresent()) + buffer[0] |= kXBit; + if (hdr_info_.nonReference) + buffer[0] |= kNBit; + if (packet_info.first_packet) + buffer[0] |= kSBit; + + const int extension_length = WriteExtensionFields(buffer, buffer_length); + if (extension_length < 0) + return -1; + + memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length], + &payload_data_[packet_info.payload_start_pos], + packet_info.size); + + // Return total length of written data. + return packet_info.size + vp8_fixed_payload_descriptor_bytes_ + + extension_length; +} + +int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer, + size_t buffer_length) const { + size_t extension_length = 0; + if (XFieldPresent()) { + uint8_t* x_field = buffer + vp8_fixed_payload_descriptor_bytes_; + *x_field = 0; + extension_length = 1; // One octet for the X field. + if (PictureIdPresent()) { + if (WritePictureIDFields( + x_field, buffer, buffer_length, &extension_length) < 0) { + return -1; + } + } + if (TL0PicIdxFieldPresent()) { + if (WriteTl0PicIdxFields( + x_field, buffer, buffer_length, &extension_length) < 0) { + return -1; + } + } + if (TIDFieldPresent() || KeyIdxFieldPresent()) { + if (WriteTIDAndKeyIdxFields( + x_field, buffer, buffer_length, &extension_length) < 0) { + return -1; + } + } + RTC_DCHECK_EQ(extension_length, PayloadDescriptorExtraLength()); + } + return static_cast<int>(extension_length); +} + +int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field, + uint8_t* buffer, + size_t buffer_length, + size_t* extension_length) const { + *x_field |= kIBit; + RTC_DCHECK_GE(buffer_length, + vp8_fixed_payload_descriptor_bytes_ + *extension_length); + const int pic_id_length = WritePictureID( + buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length, + buffer_length - vp8_fixed_payload_descriptor_bytes_ - *extension_length); + if (pic_id_length < 0) + return -1; + *extension_length += pic_id_length; + return 0; +} + +int RtpPacketizerVp8::WritePictureID(uint8_t* buffer, + size_t buffer_length) const { + const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId); + size_t picture_id_len = PictureIdLength(); + if (picture_id_len > buffer_length) + return -1; + if (picture_id_len == 2) { + buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F); + buffer[1] = pic_id & 0xFF; + } else if (picture_id_len == 1) { + buffer[0] = pic_id & 0x7F; + } + return static_cast<int>(picture_id_len); +} + +int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field, + uint8_t* buffer, + size_t buffer_length, + size_t* extension_length) const { + if (buffer_length < + vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) { + return -1; + } + *x_field |= kLBit; + buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] = + hdr_info_.tl0PicIdx; + ++*extension_length; + return 0; +} + +int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field, + uint8_t* buffer, + size_t buffer_length, + size_t* extension_length) const { + if (buffer_length < + vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) { + return -1; + } + uint8_t* data_field = + &buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length]; + *data_field = 0; + if (TIDFieldPresent()) { + *x_field |= kTBit; + *data_field |= hdr_info_.temporalIdx << 6; + *data_field |= hdr_info_.layerSync ? kYBit : 0; + } + if (KeyIdxFieldPresent()) { + *x_field |= kKBit; + *data_field |= (hdr_info_.keyIdx & kKeyIdxField); + } + ++*extension_length; + return 0; +} + +size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const { + size_t length_bytes = PictureIdLength(); + if (TL0PicIdxFieldPresent()) + ++length_bytes; + if (TIDFieldPresent() || KeyIdxFieldPresent()) + ++length_bytes; + if (length_bytes > 0) + ++length_bytes; // Include the extension field. + return length_bytes; +} + +size_t RtpPacketizerVp8::PictureIdLength() const { + if (hdr_info_.pictureId == kNoPictureId) { + return 0; + } + return 2; +} + +bool RtpPacketizerVp8::XFieldPresent() const { + return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() || + KeyIdxFieldPresent()); +} + +bool RtpPacketizerVp8::TIDFieldPresent() const { + return (hdr_info_.temporalIdx != kNoTemporalIdx); +} + +bool RtpPacketizerVp8::KeyIdxFieldPresent() const { + return (hdr_info_.keyIdx != kNoKeyIdx); +} + +bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const { + return (hdr_info_.tl0PicIdx != kNoTl0PicIdx); +} + +// +// VP8 format: +// +// Payload descriptor +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |X|R|N|S|PartID | (REQUIRED) +// +-+-+-+-+-+-+-+-+ +// X: |I|L|T|K| RSV | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// I: | PictureID | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// L: | TL0PICIDX | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// T/K: |TID:Y| KEYIDX | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// +// Payload header (considered part of the actual payload, sent to decoder) +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |Size0|H| VER |P| +// +-+-+-+-+-+-+-+-+ +// | ... | +// + + +bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload, + const uint8_t* payload_data, + size_t payload_data_length) { + RTC_DCHECK(parsed_payload); + if (payload_data_length == 0) { + RTC_LOG(LS_ERROR) << "Empty payload."; + return false; + } + + // Parse mandatory first byte of payload descriptor. + bool extension = (*payload_data & 0x80) ? true : false; // X bit + bool beginning_of_partition = (*payload_data & 0x10) ? true : false; // S bit + int partition_id = (*payload_data & 0x0F); // PartID field + + parsed_payload->type.Video.width = 0; + parsed_payload->type.Video.height = 0; + parsed_payload->type.Video.is_first_packet_in_frame = + beginning_of_partition && (partition_id == 0); + parsed_payload->type.Video.simulcastIdx = 0; + parsed_payload->type.Video.codec = kRtpVideoVp8; + parsed_payload->type.Video.codecHeader.VP8.nonReference = + (*payload_data & 0x20) ? true : false; // N bit + parsed_payload->type.Video.codecHeader.VP8.partitionId = partition_id; + parsed_payload->type.Video.codecHeader.VP8.beginningOfPartition = + beginning_of_partition; + parsed_payload->type.Video.codecHeader.VP8.pictureId = kNoPictureId; + parsed_payload->type.Video.codecHeader.VP8.tl0PicIdx = kNoTl0PicIdx; + parsed_payload->type.Video.codecHeader.VP8.temporalIdx = kNoTemporalIdx; + parsed_payload->type.Video.codecHeader.VP8.layerSync = false; + parsed_payload->type.Video.codecHeader.VP8.keyIdx = kNoKeyIdx; + + if (partition_id > 8) { + // Weak check for corrupt payload_data: PartID MUST NOT be larger than 8. + return false; + } + + // Advance payload_data and decrease remaining payload size. + payload_data++; + if (payload_data_length <= 1) { + RTC_LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!"; + return false; + } + payload_data_length--; + + if (extension) { + const int parsed_bytes = + ParseVP8Extension(&parsed_payload->type.Video.codecHeader.VP8, + payload_data, + payload_data_length); + if (parsed_bytes < 0) + return false; + payload_data += parsed_bytes; + payload_data_length -= parsed_bytes; + if (payload_data_length == 0) { + RTC_LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!"; + return false; + } + } + + // Read P bit from payload header (only at beginning of first partition). + if (beginning_of_partition && partition_id == 0) { + parsed_payload->frame_type = + (*payload_data & 0x01) ? kVideoFrameDelta : kVideoFrameKey; + } else { + parsed_payload->frame_type = kVideoFrameDelta; + } + + if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) != + 0) { + return false; + } + + parsed_payload->payload = payload_data; + parsed_payload->payload_length = payload_data_length; + return true; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h new file mode 100644 index 0000000000..893086430a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2011 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 file contains the declaration of the VP8 packetizer class. + * A packetizer object is created for each encoded video frame. The + * constructor is called with the payload data and size, + * together with the fragmentation information and a packetizer mode + * of choice. Alternatively, if no fragmentation info is available, the + * second constructor can be used with only payload data and size; in that + * case the mode kEqualSize is used. + * + * After creating the packetizer, the method NextPacket is called + * repeatedly to get all packets for the frame. The method returns + * false as long as there are more packets left to fetch. + */ + +#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_ + +#include <queue> +#include <string> +#include <vector> + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "rtc_base/constructormagic.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +// Packetizer for VP8. +class RtpPacketizerVp8 : public RtpPacketizer { + public: + // Initialize with payload from encoder. + // The payload_data must be exactly one encoded VP8 frame. + RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info, + size_t max_payload_len, + size_t last_packet_reduction_len); + + virtual ~RtpPacketizerVp8(); + + size_t SetPayloadData(const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) override; + + // Get the next payload with VP8 payload header. + // Write payload and set marker bit of the |packet|. + // Returns true on success, false otherwise. + bool NextPacket(RtpPacketToSend* packet) override; + + std::string ToString() override; + + private: + typedef struct { + size_t payload_start_pos; + size_t size; + bool first_packet; + } InfoStruct; + typedef std::queue<InfoStruct> InfoQueue; + + static const int kXBit = 0x80; + static const int kNBit = 0x20; + static const int kSBit = 0x10; + static const int kPartIdField = 0x0F; + static const int kKeyIdxField = 0x1F; + static const int kIBit = 0x80; + static const int kLBit = 0x40; + static const int kTBit = 0x20; + static const int kKBit = 0x10; + static const int kYBit = 0x20; + + // Calculate all packet sizes and load to packet info queue. + int GeneratePackets(); + + // Splits given part of payload to packets with a given capacity. The last + // packet should be reduced by last_packet_reduction_len_. + void GeneratePacketsSplitPayloadBalanced(size_t payload_len, + size_t capacity); + + // Insert packet into packet queue. + void QueuePacket(size_t start_pos, + size_t packet_size, + bool first_packet); + + // Write the payload header and copy the payload to the buffer. + // The info in packet_info determines which part of the payload is written + // and what to write in the header fields. + int WriteHeaderAndPayload(const InfoStruct& packet_info, + uint8_t* buffer, + size_t buffer_length) const; + + // Write the X field and the appropriate extension fields to buffer. + // The function returns the extension length (including X field), or -1 + // on error. + int WriteExtensionFields(uint8_t* buffer, size_t buffer_length) const; + + // Set the I bit in the x_field, and write PictureID to the appropriate + // position in buffer. The function returns 0 on success, -1 otherwise. + int WritePictureIDFields(uint8_t* x_field, + uint8_t* buffer, + size_t buffer_length, + size_t* extension_length) const; + + // Set the L bit in the x_field, and write Tl0PicIdx to the appropriate + // position in buffer. The function returns 0 on success, -1 otherwise. + int WriteTl0PicIdxFields(uint8_t* x_field, + uint8_t* buffer, + size_t buffer_length, + size_t* extension_length) const; + + // Set the T and K bits in the x_field, and write TID, Y and KeyIdx to the + // appropriate position in buffer. The function returns 0 on success, + // -1 otherwise. + int WriteTIDAndKeyIdxFields(uint8_t* x_field, + uint8_t* buffer, + size_t buffer_length, + size_t* extension_length) const; + + // Write the PictureID from codec_specific_info_ to buffer. One or two + // bytes are written, depending on magnitude of PictureID. The function + // returns the number of bytes written. + int WritePictureID(uint8_t* buffer, size_t buffer_length) const; + + // Calculate and return length (octets) of the variable header fields in + // the next header (i.e., header length in addition to vp8_header_bytes_). + size_t PayloadDescriptorExtraLength() const; + + // Calculate and return length (octets) of PictureID field in the next + // header. Can be 0, 1, or 2. + size_t PictureIdLength() const; + + // Check whether each of the optional fields will be included in the header. + bool XFieldPresent() const; + bool TIDFieldPresent() const; + bool KeyIdxFieldPresent() const; + bool TL0PicIdxFieldPresent() const; + bool PictureIdPresent() const { return (PictureIdLength() > 0); } + + const uint8_t* payload_data_; + size_t payload_size_; + const size_t vp8_fixed_payload_descriptor_bytes_; // Length of VP8 payload + // descriptors' fixed part. + const RTPVideoHeaderVP8 hdr_info_; + const size_t max_payload_len_; + const size_t last_packet_reduction_len_; + InfoQueue packets_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp8); +}; + +// Depacketizer for VP8. +class RtpDepacketizerVp8 : public RtpDepacketizer { + public: + virtual ~RtpDepacketizerVp8() {} + + bool Parse(ParsedPayload* parsed_payload, + const uint8_t* payload_data, + size_t payload_data_length) override; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc new file mode 100644 index 0000000000..62d7c3c3bf --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc @@ -0,0 +1,243 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h" + +#include "test/gtest.h" + +namespace webrtc { + +namespace test { + +constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; + +RtpFormatVp8TestHelper::RtpFormatVp8TestHelper(const RTPVideoHeaderVP8* hdr) + : packet_(kNoExtensions), + payload_data_(NULL), + data_ptr_(NULL), + fragmentation_(NULL), + hdr_info_(hdr), + payload_start_(0), + payload_size_(0), + sloppy_partitioning_(false), + inited_(false) {} + +RtpFormatVp8TestHelper::~RtpFormatVp8TestHelper() { + delete fragmentation_; + delete [] payload_data_; +} + +bool RtpFormatVp8TestHelper::Init(const size_t* partition_sizes, + size_t num_partitions) { + if (inited_) return false; + fragmentation_ = new RTPFragmentationHeader; + fragmentation_->VerifyAndAllocateFragmentationHeader(num_partitions); + payload_size_ = 0; + // Calculate sum payload size. + for (size_t p = 0; p < num_partitions; ++p) { + payload_size_ += partition_sizes[p]; + } + payload_data_ = new uint8_t[payload_size_]; + size_t j = 0; + // Loop through the partitions again. + for (size_t p = 0; p < num_partitions; ++p) { + fragmentation_->fragmentationLength[p] = partition_sizes[p]; + fragmentation_->fragmentationOffset[p] = j; + for (size_t i = 0; i < partition_sizes[p]; ++i) { + assert(j < payload_size_); + payload_data_[j++] = p; // Set the payload value to the partition index. + } + } + data_ptr_ = payload_data_; + inited_ = true; + return true; +} + +void RtpFormatVp8TestHelper::GetAllPacketsAndCheck( + RtpPacketizerVp8* packetizer, + const size_t* expected_sizes, + const int* expected_part, + const bool* expected_frag_start, + size_t expected_num_packets) { + ASSERT_TRUE(inited_); + for (size_t i = 0; i < expected_num_packets; ++i) { + std::ostringstream ss; + ss << "Checking packet " << i; + SCOPED_TRACE(ss.str()); + EXPECT_TRUE(packetizer->NextPacket(&packet_)); + CheckPacket(expected_sizes[i], i + 1 == expected_num_packets, + expected_frag_start[i]); + } +} + +// Payload descriptor +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |X|R|N|S|PartID | (REQUIRED) +// +-+-+-+-+-+-+-+-+ +// X: |I|L|T|K| RSV | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// I: | PictureID | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// L: | TL0PICIDX | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// T/K: | TID | KEYIDX | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ + +// First octet tests. +#define EXPECT_BIT_EQ(x, n, a) EXPECT_EQ((((x) >> (n)) & 0x1), a) + +#define EXPECT_RSV_ZERO(x) EXPECT_EQ(((x) & 0xE0), 0) + +#define EXPECT_BIT_X_EQ(x, a) EXPECT_BIT_EQ(x, 7, a) + +#define EXPECT_BIT_N_EQ(x, a) EXPECT_BIT_EQ(x, 5, a) + +#define EXPECT_BIT_S_EQ(x, a) EXPECT_BIT_EQ(x, 4, a) + +#define EXPECT_PART_ID_EQ(x, a) EXPECT_EQ(((x) & 0x0F), a) + +// Extension fields tests +#define EXPECT_BIT_I_EQ(x, a) EXPECT_BIT_EQ(x, 7, a) + +#define EXPECT_BIT_L_EQ(x, a) EXPECT_BIT_EQ(x, 6, a) + +#define EXPECT_BIT_T_EQ(x, a) EXPECT_BIT_EQ(x, 5, a) + +#define EXPECT_BIT_K_EQ(x, a) EXPECT_BIT_EQ(x, 4, a) + +#define EXPECT_TID_EQ(x, a) EXPECT_EQ((((x) & 0xC0) >> 6), a) + +#define EXPECT_BIT_Y_EQ(x, a) EXPECT_BIT_EQ(x, 5, a) + +#define EXPECT_KEYIDX_EQ(x, a) EXPECT_EQ(((x) & 0x1F), a) + +void RtpFormatVp8TestHelper::CheckHeader(bool frag_start) { + payload_start_ = 1; + rtc::ArrayView<const uint8_t> buffer = packet_.payload(); + EXPECT_BIT_EQ(buffer[0], 6, 0); // Check reserved bit. + + if (hdr_info_->pictureId != kNoPictureId || + hdr_info_->temporalIdx != kNoTemporalIdx || + hdr_info_->tl0PicIdx != kNoTl0PicIdx || + hdr_info_->keyIdx != kNoKeyIdx) { + EXPECT_BIT_X_EQ(buffer[0], 1); + ++payload_start_; + CheckPictureID(); + CheckTl0PicIdx(); + CheckTIDAndKeyIdx(); + } else { + EXPECT_BIT_X_EQ(buffer[0], 0); + } + + EXPECT_BIT_N_EQ(buffer[0], hdr_info_->nonReference ? 1 : 0); + EXPECT_BIT_S_EQ(buffer[0], frag_start ? 1 : 0); + + // Check partition index. + if (!sloppy_partitioning_) { + // The test payload data is constructed such that the payload value is the + // same as the partition index. + EXPECT_EQ(buffer[0] & 0x0F, buffer[payload_start_]); + } else { + // Partition should be set to 0. + EXPECT_EQ(buffer[0] & 0x0F, 0); + } +} + +// Verify that the I bit and the PictureID field are both set in accordance +// with the information in hdr_info_->pictureId. +void RtpFormatVp8TestHelper::CheckPictureID() { + auto buffer = packet_.payload(); + if (hdr_info_->pictureId != kNoPictureId) { + EXPECT_BIT_I_EQ(buffer[1], 1); + EXPECT_BIT_EQ(buffer[payload_start_], 7, 1); + EXPECT_EQ(buffer[payload_start_] & 0x7F, + (hdr_info_->pictureId >> 8) & 0x7F); + EXPECT_EQ(buffer[payload_start_ + 1], hdr_info_->pictureId & 0xFF); + payload_start_ += 2; + } else { + EXPECT_BIT_I_EQ(buffer[1], 0); + } +} + +// Verify that the L bit and the TL0PICIDX field are both set in accordance +// with the information in hdr_info_->tl0PicIdx. +void RtpFormatVp8TestHelper::CheckTl0PicIdx() { + auto buffer = packet_.payload(); + if (hdr_info_->tl0PicIdx != kNoTl0PicIdx) { + EXPECT_BIT_L_EQ(buffer[1], 1); + EXPECT_EQ(buffer[payload_start_], hdr_info_->tl0PicIdx); + ++payload_start_; + } else { + EXPECT_BIT_L_EQ(buffer[1], 0); + } +} + +// Verify that the T bit and the TL0PICIDX field, and the K bit and KEYIDX +// field are all set in accordance with the information in +// hdr_info_->temporalIdx and hdr_info_->keyIdx, respectively. +void RtpFormatVp8TestHelper::CheckTIDAndKeyIdx() { + auto buffer = packet_.payload(); + if (hdr_info_->temporalIdx == kNoTemporalIdx && + hdr_info_->keyIdx == kNoKeyIdx) { + EXPECT_BIT_T_EQ(buffer[1], 0); + EXPECT_BIT_K_EQ(buffer[1], 0); + return; + } + if (hdr_info_->temporalIdx != kNoTemporalIdx) { + EXPECT_BIT_T_EQ(buffer[1], 1); + EXPECT_TID_EQ(buffer[payload_start_], hdr_info_->temporalIdx); + EXPECT_BIT_Y_EQ(buffer[payload_start_], hdr_info_->layerSync ? 1 : 0); + } else { + EXPECT_BIT_T_EQ(buffer[1], 0); + EXPECT_TID_EQ(buffer[payload_start_], 0); + EXPECT_BIT_Y_EQ(buffer[payload_start_], 0); + } + if (hdr_info_->keyIdx != kNoKeyIdx) { + EXPECT_BIT_K_EQ(buffer[1], 1); + EXPECT_KEYIDX_EQ(buffer[payload_start_], hdr_info_->keyIdx); + } else { + EXPECT_BIT_K_EQ(buffer[1], 0); + EXPECT_KEYIDX_EQ(buffer[payload_start_], 0); + } + ++payload_start_; +} + +// Verify that the payload (i.e., after the headers) of the packet stored in +// buffer_ is identical to the expected (as found in data_ptr_). +void RtpFormatVp8TestHelper::CheckPayload() { + auto buffer = packet_.payload(); + size_t payload_end = buffer.size(); + for (size_t i = payload_start_; i < payload_end; ++i, ++data_ptr_) + EXPECT_EQ(buffer[i], *data_ptr_); +} + +// Verify that the input variable "last" agrees with the position of data_ptr_. +// If data_ptr_ has advanced payload_size_ bytes from the start (payload_data_) +// we are at the end and last should be true. Otherwise, it should be false. +void RtpFormatVp8TestHelper::CheckLast(bool last) const { + EXPECT_EQ(last, data_ptr_ == payload_data_ + payload_size_); +} + +// Verify the contents of a packet. Check the length versus expected_bytes, +// the header, payload, and "last" flag. +void RtpFormatVp8TestHelper::CheckPacket(size_t expect_bytes, + bool last, + bool frag_start) { + EXPECT_EQ(expect_bytes, packet_.payload_size()); + CheckHeader(frag_start); + CheckPayload(); + CheckLast(last); +} + +} // namespace test + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h new file mode 100644 index 0000000000..1ed63abdee --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 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 file contains the class RtpFormatVp8TestHelper. The class is +// responsible for setting up a fake VP8 bitstream according to the +// RTPVideoHeaderVP8 header, and partition information. After initialization, +// an RTPFragmentationHeader is provided so that the tester can create a +// packetizer. The packetizer can then be provided to this helper class, which +// will then extract all packets and compare to the expected outcome. + +#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_TEST_HELPER_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_TEST_HELPER_H_ + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/rtp_format_vp8.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/constructormagic.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +namespace test { + +class RtpFormatVp8TestHelper { + public: + explicit RtpFormatVp8TestHelper(const RTPVideoHeaderVP8* hdr); + ~RtpFormatVp8TestHelper(); + bool Init(const size_t* partition_sizes, size_t num_partitions); + void GetAllPacketsAndCheck(RtpPacketizerVp8* packetizer, + const size_t* expected_sizes, + const int* expected_part, + const bool* expected_frag_start, + size_t expected_num_packets); + + uint8_t* payload_data() const { return payload_data_; } + size_t payload_size() const { return payload_size_; } + RTPFragmentationHeader* fragmentation() const { return fragmentation_; } + size_t buffer_size() const { + static constexpr size_t kVp8PayloadDescriptorMaxSize = 6; + return payload_size_ + kVp8PayloadDescriptorMaxSize; + } + void set_sloppy_partitioning(bool value) { sloppy_partitioning_ = value; } + + private: + void CheckHeader(bool frag_start); + void CheckPictureID(); + void CheckTl0PicIdx(); + void CheckTIDAndKeyIdx(); + void CheckPayload(); + void CheckLast(bool last) const; + void CheckPacket(size_t expect_bytes, bool last, bool frag_start); + + RtpPacketToSend packet_; + uint8_t* payload_data_; + uint8_t* data_ptr_; + RTPFragmentationHeader* fragmentation_; + const RTPVideoHeaderVP8* hdr_info_; + int payload_start_; + size_t payload_size_; + bool sloppy_partitioning_; + bool inited_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpFormatVp8TestHelper); +}; + +} // namespace test + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_TEST_HELPER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc new file mode 100644 index 0000000000..0095560e5d --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc @@ -0,0 +1,485 @@ +/* + * 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 <memory> + +#include "modules/rtp_rtcp/source/rtp_format_vp8.h" +#include "modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "typedefs.h" // NOLINT(build/include) + +#define CHECK_ARRAY_SIZE(expected_size, array) \ + static_assert(expected_size == sizeof(array) / sizeof(array[0]), \ + "check array size"); + +namespace webrtc { +namespace { + +using ::testing::ElementsAreArray; +using ::testing::make_tuple; + +constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; +// Payload descriptor +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |X|R|N|S|PartID | (REQUIRED) +// +-+-+-+-+-+-+-+-+ +// X: |I|L|T|K| RSV | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// I: | PictureID | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// L: | TL0PICIDX | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// T/K: |TID:Y| KEYIDX | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ +// +// Payload header +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |Size0|H| VER |P| +// +-+-+-+-+-+-+-+-+ +// | Size1 | +// +-+-+-+-+-+-+-+-+ +// | Size2 | +// +-+-+-+-+-+-+-+-+ +// | Bytes 4..N of | +// | VP8 payload | +// : : +// +-+-+-+-+-+-+-+-+ +// | OPTIONAL RTP | +// | padding | +// : : +// +-+-+-+-+-+-+-+-+ +void VerifyBasicHeader(RTPTypeHeader* type, bool N, bool S, int part_id) { + ASSERT_TRUE(type != NULL); + EXPECT_EQ(N, type->Video.codecHeader.VP8.nonReference); + EXPECT_EQ(S, type->Video.codecHeader.VP8.beginningOfPartition); + EXPECT_EQ(part_id, type->Video.codecHeader.VP8.partitionId); +} + +void VerifyExtensions(RTPTypeHeader* type, + int16_t picture_id, /* I */ + int16_t tl0_pic_idx, /* L */ + uint8_t temporal_idx, /* T */ + int key_idx /* K */) { + ASSERT_TRUE(type != NULL); + EXPECT_EQ(picture_id, type->Video.codecHeader.VP8.pictureId); + EXPECT_EQ(tl0_pic_idx, type->Video.codecHeader.VP8.tl0PicIdx); + EXPECT_EQ(temporal_idx, type->Video.codecHeader.VP8.temporalIdx); + EXPECT_EQ(key_idx, type->Video.codecHeader.VP8.keyIdx); +} +} // namespace + +class RtpPacketizerVp8Test : public ::testing::Test { + protected: + RtpPacketizerVp8Test() : helper_(NULL) {} + virtual void TearDown() { delete helper_; } + bool Init(const size_t* partition_sizes, size_t num_partitions) { + hdr_info_.pictureId = kNoPictureId; + hdr_info_.nonReference = false; + hdr_info_.temporalIdx = kNoTemporalIdx; + hdr_info_.layerSync = false; + hdr_info_.tl0PicIdx = kNoTl0PicIdx; + hdr_info_.keyIdx = kNoKeyIdx; + if (helper_ != NULL) + return false; + helper_ = new test::RtpFormatVp8TestHelper(&hdr_info_); + return helper_->Init(partition_sizes, num_partitions); + } + + RTPVideoHeaderVP8 hdr_info_; + test::RtpFormatVp8TestHelper* helper_; +}; + +// Verify that EqualSize mode is forced if fragmentation info is missing. +TEST_F(RtpPacketizerVp8Test, TestEqualSizeModeFallback) { + const size_t kSizeVector[] = {10, 10, 10}; + const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); + ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); + + hdr_info_.pictureId = 200; // > 0x7F should produce 2-byte PictureID + const size_t kMaxPayloadSize = 12; // Small enough to produce 4 packets. + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0); + size_t num_packets = packetizer.SetPayloadData( + helper_->payload_data(), helper_->payload_size(), nullptr); + + // Expecting three full packets, and one with the remainder. + const size_t kExpectedSizes[] = {11, 11, 12, 12}; + const int kExpectedPart[] = {0, 0, 0, 0}; // Always 0 for equal size mode. + // Frag start only true for first packet in equal size mode. + const bool kExpectedFragStart[] = {true, false, false, false}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); + ASSERT_EQ(num_packets, kExpectedNum); + + helper_->set_sloppy_partitioning(true); + helper_->GetAllPacketsAndCheck(&packetizer, + kExpectedSizes, + kExpectedPart, + kExpectedFragStart, + kExpectedNum); +} + +TEST_F(RtpPacketizerVp8Test, TestEqualSizeWithLastPacketReduction) { + const size_t kSizeVector[] = {30, 10, 3}; + const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); + ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); + + hdr_info_.pictureId = 200; + const size_t kMaxPayloadSize = 15; // Small enough to produce 5 packets. + const size_t kLastPacketReduction = 5; + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kLastPacketReduction); + size_t num_packets = packetizer.SetPayloadData( + helper_->payload_data(), helper_->payload_size(), nullptr); + + // Calculated by hand. VP8 payload descriptors are 4 byte each. 5 packets is + // minimum possible to fit 43 payload bytes into packets with capacity of + // 15 - 4 = 11 and leave 5 free bytes in the last packet. All packets are + // almost equal in size, even last packet if counted with free space (which + // will be filled up the stack by extra long RTP header). + const size_t kExpectedSizes[] = {13, 13, 14, 14, 9}; + const int kExpectedPart[] = {0, 0, 0, 0, 0}; // Always 0 for equal size mode. + // Frag start only true for first packet in equal size mode. + const bool kExpectedFragStart[] = {true, false, false, false, false}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); + ASSERT_EQ(num_packets, kExpectedNum); + + helper_->set_sloppy_partitioning(true); + helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart, + kExpectedFragStart, kExpectedNum); +} + +// Verify that non-reference bit is set. EqualSize mode fallback is expected. +TEST_F(RtpPacketizerVp8Test, TestNonReferenceBit) { + const size_t kSizeVector[] = {10, 10, 10}; + const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); + ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); + + hdr_info_.nonReference = true; + const size_t kMaxPayloadSize = 25; // Small enough to produce two packets. + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0); + size_t num_packets = packetizer.SetPayloadData( + helper_->payload_data(), helper_->payload_size(), nullptr); + + // EqualSize mode => First packet full; other not. + const size_t kExpectedSizes[] = {16, 16}; + const int kExpectedPart[] = {0, 0}; // Always 0 for equal size mode. + // Frag start only true for first packet in equal size mode. + const bool kExpectedFragStart[] = {true, false}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); + ASSERT_EQ(num_packets, kExpectedNum); + + helper_->set_sloppy_partitioning(true); + helper_->GetAllPacketsAndCheck(&packetizer, + kExpectedSizes, + kExpectedPart, + kExpectedFragStart, + kExpectedNum); +} + +// Verify Tl0PicIdx and TID fields, and layerSync bit. +TEST_F(RtpPacketizerVp8Test, TestTl0PicIdxAndTID) { + const size_t kSizeVector[] = {10, 10, 10}; + const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); + ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); + + hdr_info_.tl0PicIdx = 117; + hdr_info_.temporalIdx = 2; + hdr_info_.layerSync = true; + // kMaxPayloadSize is only limited by allocated buffer size. + const size_t kMaxPayloadSize = helper_->buffer_size(); + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0); + size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(), + helper_->payload_size(), + helper_->fragmentation()); + + // Expect one single packet of payload_size() + 4 bytes header. + const size_t kExpectedSizes[1] = {helper_->payload_size() + 4}; + const int kExpectedPart[1] = {0}; // Packet starts with partition 0. + const bool kExpectedFragStart[1] = {true}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); + ASSERT_EQ(num_packets, kExpectedNum); + + helper_->GetAllPacketsAndCheck(&packetizer, + kExpectedSizes, + kExpectedPart, + kExpectedFragStart, + kExpectedNum); +} + +// Verify KeyIdx field. +TEST_F(RtpPacketizerVp8Test, TestKeyIdx) { + const size_t kSizeVector[] = {10, 10, 10}; + const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); + ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); + + hdr_info_.keyIdx = 17; + // kMaxPayloadSize is only limited by allocated buffer size. + const size_t kMaxPayloadSize = helper_->buffer_size(); + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0); + size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(), + helper_->payload_size(), + helper_->fragmentation()); + + // Expect one single packet of payload_size() + 3 bytes header. + const size_t kExpectedSizes[1] = {helper_->payload_size() + 3}; + const int kExpectedPart[1] = {0}; // Packet starts with partition 0. + const bool kExpectedFragStart[1] = {true}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); + ASSERT_EQ(num_packets, kExpectedNum); + + helper_->GetAllPacketsAndCheck(&packetizer, + kExpectedSizes, + kExpectedPart, + kExpectedFragStart, + kExpectedNum); +} + +// Verify TID field and KeyIdx field in combination. +TEST_F(RtpPacketizerVp8Test, TestTIDAndKeyIdx) { + const size_t kSizeVector[] = {10, 10, 10}; + const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector); + ASSERT_TRUE(Init(kSizeVector, kNumPartitions)); + + hdr_info_.temporalIdx = 1; + hdr_info_.keyIdx = 5; + // kMaxPayloadSize is only limited by allocated buffer size. + const size_t kMaxPayloadSize = helper_->buffer_size(); + RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0); + size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(), + helper_->payload_size(), + helper_->fragmentation()); + + // Expect one single packet of payload_size() + 3 bytes header. + const size_t kExpectedSizes[1] = {helper_->payload_size() + 3}; + const int kExpectedPart[1] = {0}; // Packet starts with partition 0. + const bool kExpectedFragStart[1] = {true}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart); + CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart); + ASSERT_EQ(num_packets, kExpectedNum); + + helper_->GetAllPacketsAndCheck(&packetizer, + kExpectedSizes, + kExpectedPart, + kExpectedFragStart, + kExpectedNum); +} + +class RtpDepacketizerVp8Test : public ::testing::Test { + protected: + RtpDepacketizerVp8Test() + : depacketizer_(RtpDepacketizer::Create(kRtpVideoVp8)) {} + + void ExpectPacket(RtpDepacketizer::ParsedPayload* parsed_payload, + const uint8_t* data, + size_t length) { + ASSERT_TRUE(parsed_payload != NULL); + EXPECT_THAT(std::vector<uint8_t>( + parsed_payload->payload, + parsed_payload->payload + parsed_payload->payload_length), + ::testing::ElementsAreArray(data, length)); + } + + std::unique_ptr<RtpDepacketizer> depacketizer_; +}; + +TEST_F(RtpDepacketizerVp8Test, BasicHeader) { + const uint8_t kHeaderLength = 1; + uint8_t packet[4] = {0}; + packet[0] = 0x14; // Binary 0001 0100; S = 1, PartID = 4. + packet[1] = 0x01; // P frame. + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); + EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); + VerifyBasicHeader(&payload.type, 0, 1, 4); + VerifyExtensions( + &payload.type, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); +} + +TEST_F(RtpDepacketizerVp8Test, PictureID) { + const uint8_t kHeaderLength1 = 3; + const uint8_t kHeaderLength2 = 4; + const uint8_t kPictureId = 17; + uint8_t packet[10] = {0}; + packet[0] = 0xA0; + packet[1] = 0x80; + packet[2] = kPictureId; + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength1, sizeof(packet) - kHeaderLength1); + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); + EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); + VerifyBasicHeader(&payload.type, 1, 0, 0); + VerifyExtensions( + &payload.type, kPictureId, kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); + + // Re-use packet, but change to long PictureID. + packet[2] = 0x80 | kPictureId; + packet[3] = kPictureId; + + payload = RtpDepacketizer::ParsedPayload(); + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength2, sizeof(packet) - kHeaderLength2); + VerifyBasicHeader(&payload.type, 1, 0, 0); + VerifyExtensions(&payload.type, + (kPictureId << 8) + kPictureId, + kNoTl0PicIdx, + kNoTemporalIdx, + kNoKeyIdx); +} + +TEST_F(RtpDepacketizerVp8Test, Tl0PicIdx) { + const uint8_t kHeaderLength = 3; + const uint8_t kTl0PicIdx = 17; + uint8_t packet[13] = {0}; + packet[0] = 0x90; + packet[1] = 0x40; + packet[2] = kTl0PicIdx; + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); + VerifyBasicHeader(&payload.type, 0, 1, 0); + VerifyExtensions( + &payload.type, kNoPictureId, kTl0PicIdx, kNoTemporalIdx, kNoKeyIdx); +} + +TEST_F(RtpDepacketizerVp8Test, TIDAndLayerSync) { + const uint8_t kHeaderLength = 3; + uint8_t packet[10] = {0}; + packet[0] = 0x88; + packet[1] = 0x20; + packet[2] = 0x80; // TID(2) + LayerSync(false) + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); + EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); + VerifyBasicHeader(&payload.type, 0, 0, 8); + VerifyExtensions(&payload.type, kNoPictureId, kNoTl0PicIdx, 2, kNoKeyIdx); + EXPECT_FALSE(payload.type.Video.codecHeader.VP8.layerSync); +} + +TEST_F(RtpDepacketizerVp8Test, KeyIdx) { + const uint8_t kHeaderLength = 3; + const uint8_t kKeyIdx = 17; + uint8_t packet[10] = {0}; + packet[0] = 0x88; + packet[1] = 0x10; // K = 1. + packet[2] = kKeyIdx; + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); + EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); + VerifyBasicHeader(&payload.type, 0, 0, 8); + VerifyExtensions( + &payload.type, kNoPictureId, kNoTl0PicIdx, kNoTemporalIdx, kKeyIdx); +} + +TEST_F(RtpDepacketizerVp8Test, MultipleExtensions) { + const uint8_t kHeaderLength = 6; + uint8_t packet[10] = {0}; + packet[0] = 0x88; + packet[1] = 0x80 | 0x40 | 0x20 | 0x10; + packet[2] = 0x80 | 17; // PictureID, high 7 bits. + packet[3] = 17; // PictureID, low 8 bits. + packet[4] = 42; // Tl0PicIdx. + packet[5] = 0x40 | 0x20 | 0x11; // TID(1) + LayerSync(true) + KEYIDX(17). + RtpDepacketizer::ParsedPayload payload; + + ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet))); + ExpectPacket( + &payload, packet + kHeaderLength, sizeof(packet) - kHeaderLength); + EXPECT_EQ(kVideoFrameDelta, payload.frame_type); + EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); + VerifyBasicHeader(&payload.type, 0, 0, 8); + VerifyExtensions(&payload.type, (17 << 8) + 17, 42, 1, 17); +} + +TEST_F(RtpDepacketizerVp8Test, TooShortHeader) { + uint8_t packet[4] = {0}; + packet[0] = 0x88; + packet[1] = 0x80 | 0x40 | 0x20 | 0x10; // All extensions are enabled... + packet[2] = 0x80 | 17; // ... but only 2 bytes PictureID is provided. + packet[3] = 17; // PictureID, low 8 bits. + RtpDepacketizer::ParsedPayload payload; + + EXPECT_FALSE(depacketizer_->Parse(&payload, packet, sizeof(packet))); +} + +TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) { + const uint8_t kHeaderLength = 5; + uint8_t data[10] = {0}; + RtpPacketToSend packet(kNoExtensions); + RTPVideoHeaderVP8 input_header; + input_header.nonReference = true; + input_header.pictureId = 300; + input_header.temporalIdx = 1; + input_header.layerSync = false; + input_header.tl0PicIdx = kNoTl0PicIdx; // Disable. + input_header.keyIdx = 31; + RtpPacketizerVp8 packetizer(input_header, 20, 0); + EXPECT_EQ(packetizer.SetPayloadData(data, 10, NULL), 1u); + ASSERT_TRUE(packetizer.NextPacket(&packet)); + EXPECT_TRUE(packet.Marker()); + + auto rtp_payload = packet.payload(); + RtpDepacketizer::ParsedPayload payload; + ASSERT_TRUE( + depacketizer_->Parse(&payload, rtp_payload.data(), rtp_payload.size())); + auto vp8_payload = rtp_payload.subview(kHeaderLength); + ExpectPacket(&payload, vp8_payload.data(), vp8_payload.size()); + EXPECT_EQ(kVideoFrameKey, payload.frame_type); + EXPECT_EQ(kRtpVideoVp8, payload.type.Video.codec); + VerifyBasicHeader(&payload.type, 1, 1, 0); + VerifyExtensions(&payload.type, + input_header.pictureId, + input_header.tl0PicIdx, + input_header.temporalIdx, + input_header.keyIdx); + EXPECT_EQ(payload.type.Video.codecHeader.VP8.layerSync, + input_header.layerSync); +} + +TEST_F(RtpDepacketizerVp8Test, TestEmptyPayload) { + // Using a wild pointer to crash on accesses from inside the depacketizer. + uint8_t* garbage_ptr = reinterpret_cast<uint8_t*>(0x4711); + RtpDepacketizer::ParsedPayload payload; + EXPECT_FALSE(depacketizer_->Parse(&payload, garbage_ptr, 0)); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc new file mode 100644 index 0000000000..bb3edfced7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc @@ -0,0 +1,765 @@ +/* + * 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. + */ + +#include "modules/rtp_rtcp/source/rtp_format_vp9.h" + +#include <assert.h> +#include <string.h> + +#include <cmath> + +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/bitbuffer.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +#define RETURN_FALSE_ON_ERROR(x) \ + if (!(x)) { \ + return false; \ + } + +namespace webrtc { +namespace { +// Length of VP9 payload descriptors' fixed part. +const size_t kFixedPayloadDescriptorBytes = 1; + +const uint32_t kReservedBitValue0 = 0; + +uint8_t TemporalIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) { + return (hdr.temporal_idx == kNoTemporalIdx) ? def : hdr.temporal_idx; +} + +uint8_t SpatialIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) { + return (hdr.spatial_idx == kNoSpatialIdx) ? def : hdr.spatial_idx; +} + +int16_t Tl0PicIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) { + return (hdr.tl0_pic_idx == kNoTl0PicIdx) ? def : hdr.tl0_pic_idx; +} + +// Picture ID: +// +// +-+-+-+-+-+-+-+-+ +// I: |M| PICTURE ID | M:0 => picture id is 7 bits. +// +-+-+-+-+-+-+-+-+ M:1 => picture id is 15 bits. +// M: | EXTENDED PID | +// +-+-+-+-+-+-+-+-+ +// +size_t PictureIdLength(const RTPVideoHeaderVP9& hdr) { + if (hdr.picture_id == kNoPictureId) + return 0; + return (hdr.max_picture_id == kMaxOneBytePictureId) ? 1 : 2; +} + +bool PictureIdPresent(const RTPVideoHeaderVP9& hdr) { + return PictureIdLength(hdr) > 0; +} + +// Layer indices: +// +// Flexible mode (F=1): Non-flexible mode (F=0): +// +// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| | T |U| S |D| +// +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ +// | TL0PICIDX | +// +-+-+-+-+-+-+-+-+ +// +size_t LayerInfoLength(const RTPVideoHeaderVP9& hdr) { + if (hdr.temporal_idx == kNoTemporalIdx && + hdr.spatial_idx == kNoSpatialIdx) { + return 0; + } + return hdr.flexible_mode ? 1 : 2; +} + +bool LayerInfoPresent(const RTPVideoHeaderVP9& hdr) { + return LayerInfoLength(hdr) > 0; +} + +// Reference indices: +// +// +-+-+-+-+-+-+-+-+ P=1,F=1: At least one reference index +// P,F: | P_DIFF |N| up to 3 times has to be specified. +// +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows +// current P_DIFF. +// +size_t RefIndicesLength(const RTPVideoHeaderVP9& hdr) { + if (!hdr.inter_pic_predicted || !hdr.flexible_mode) + return 0; + + RTC_DCHECK_GT(hdr.num_ref_pics, 0U); + RTC_DCHECK_LE(hdr.num_ref_pics, kMaxVp9RefPics); + return hdr.num_ref_pics; +} + +// Scalability structure (SS). +// +// +-+-+-+-+-+-+-+-+ +// V: | N_S |Y|G|-|-|-| +// +-+-+-+-+-+-+-+-+ -| +// Y: | WIDTH | (OPTIONAL) . +// + + . +// | | (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ . N_S + 1 times +// | HEIGHT | (OPTIONAL) . +// + + . +// | | (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ -| +// G: | N_G | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ -| +// N_G: | T |U| R |-|-| (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ -| . N_G times +// | P_DIFF | (OPTIONAL) . R times . +// +-+-+-+-+-+-+-+-+ -| -| +// +size_t SsDataLength(const RTPVideoHeaderVP9& hdr) { + if (!hdr.ss_data_available) + return 0; + + RTC_DCHECK_GT(hdr.num_spatial_layers, 0U); + RTC_DCHECK_LE(hdr.num_spatial_layers, kMaxVp9NumberOfSpatialLayers); + RTC_DCHECK_LE(hdr.gof.num_frames_in_gof, kMaxVp9FramesInGof); + size_t length = 1; // V + if (hdr.spatial_layer_resolution_present) { + length += 4 * hdr.num_spatial_layers; // Y + } + if (hdr.gof.num_frames_in_gof > 0) { + ++length; // G + } + // N_G + length += hdr.gof.num_frames_in_gof; // T, U, R + for (size_t i = 0; i < hdr.gof.num_frames_in_gof; ++i) { + RTC_DCHECK_LE(hdr.gof.num_ref_pics[i], kMaxVp9RefPics); + length += hdr.gof.num_ref_pics[i]; // R times + } + return length; +} + +size_t PayloadDescriptorLengthMinusSsData(const RTPVideoHeaderVP9& hdr) { + return kFixedPayloadDescriptorBytes + PictureIdLength(hdr) + + LayerInfoLength(hdr) + RefIndicesLength(hdr); +} + +size_t PayloadDescriptorLength(const RTPVideoHeaderVP9& hdr) { + return PayloadDescriptorLengthMinusSsData(hdr) + SsDataLength(hdr); +} + +void QueuePacket(size_t start_pos, + size_t size, + bool layer_begin, + bool layer_end, + RtpPacketizerVp9::PacketInfoQueue* packets) { + RtpPacketizerVp9::PacketInfo packet_info; + packet_info.payload_start_pos = start_pos; + packet_info.size = size; + packet_info.layer_begin = layer_begin; + packet_info.layer_end = layer_end; + packets->push(packet_info); +} + +// Picture ID: +// +// +-+-+-+-+-+-+-+-+ +// I: |M| PICTURE ID | M:0 => picture id is 7 bits. +// +-+-+-+-+-+-+-+-+ M:1 => picture id is 15 bits. +// M: | EXTENDED PID | +// +-+-+-+-+-+-+-+-+ +// +bool WritePictureId(const RTPVideoHeaderVP9& vp9, + rtc::BitBufferWriter* writer) { + bool m_bit = (PictureIdLength(vp9) == 2); + RETURN_FALSE_ON_ERROR(writer->WriteBits(m_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.picture_id, m_bit ? 15 : 7)); + return true; +} + +// Layer indices: +// +// Flexible mode (F=1): +// +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| +// +-+-+-+-+-+-+-+-+ +// +bool WriteLayerInfoCommon(const RTPVideoHeaderVP9& vp9, + rtc::BitBufferWriter* writer) { + RETURN_FALSE_ON_ERROR(writer->WriteBits(TemporalIdxField(vp9, 0), 3)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.temporal_up_switch ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(SpatialIdxField(vp9, 0), 3)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.inter_layer_predicted ? 1: 0, 1)); + return true; +} + +// Non-flexible mode (F=0): +// +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| +// +-+-+-+-+-+-+-+-+ +// | TL0PICIDX | +// +-+-+-+-+-+-+-+-+ +// +bool WriteLayerInfoNonFlexibleMode(const RTPVideoHeaderVP9& vp9, + rtc::BitBufferWriter* writer) { + RETURN_FALSE_ON_ERROR(writer->WriteUInt8(Tl0PicIdxField(vp9, 0))); + return true; +} + +bool WriteLayerInfo(const RTPVideoHeaderVP9& vp9, + rtc::BitBufferWriter* writer) { + if (!WriteLayerInfoCommon(vp9, writer)) + return false; + + if (vp9.flexible_mode) + return true; + + return WriteLayerInfoNonFlexibleMode(vp9, writer); +} + +// Reference indices: +// +// +-+-+-+-+-+-+-+-+ P=1,F=1: At least one reference index +// P,F: | P_DIFF |N| up to 3 times has to be specified. +// +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows +// current P_DIFF. +// +bool WriteRefIndices(const RTPVideoHeaderVP9& vp9, + rtc::BitBufferWriter* writer) { + if (!PictureIdPresent(vp9) || + vp9.num_ref_pics == 0 || vp9.num_ref_pics > kMaxVp9RefPics) { + return false; + } + for (uint8_t i = 0; i < vp9.num_ref_pics; ++i) { + bool n_bit = !(i == vp9.num_ref_pics - 1); + RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.pid_diff[i], 7)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(n_bit ? 1 : 0, 1)); + } + return true; +} + +// Scalability structure (SS). +// +// +-+-+-+-+-+-+-+-+ +// V: | N_S |Y|G|-|-|-| +// +-+-+-+-+-+-+-+-+ -| +// Y: | WIDTH | (OPTIONAL) . +// + + . +// | | (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ . N_S + 1 times +// | HEIGHT | (OPTIONAL) . +// + + . +// | | (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ -| +// G: | N_G | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ -| +// N_G: | T |U| R |-|-| (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ -| . N_G times +// | P_DIFF | (OPTIONAL) . R times . +// +-+-+-+-+-+-+-+-+ -| -| +// +bool WriteSsData(const RTPVideoHeaderVP9& vp9, rtc::BitBufferWriter* writer) { + RTC_DCHECK_GT(vp9.num_spatial_layers, 0U); + RTC_DCHECK_LE(vp9.num_spatial_layers, kMaxVp9NumberOfSpatialLayers); + RTC_DCHECK_LE(vp9.gof.num_frames_in_gof, kMaxVp9FramesInGof); + bool g_bit = vp9.gof.num_frames_in_gof > 0; + + RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.num_spatial_layers - 1, 3)); + RETURN_FALSE_ON_ERROR( + writer->WriteBits(vp9.spatial_layer_resolution_present ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(g_bit ? 1 : 0, 1)); // G + RETURN_FALSE_ON_ERROR(writer->WriteBits(kReservedBitValue0, 3)); + + if (vp9.spatial_layer_resolution_present) { + for (size_t i = 0; i < vp9.num_spatial_layers; ++i) { + RETURN_FALSE_ON_ERROR(writer->WriteUInt16(vp9.width[i])); + RETURN_FALSE_ON_ERROR(writer->WriteUInt16(vp9.height[i])); + } + } + if (g_bit) { + RETURN_FALSE_ON_ERROR(writer->WriteUInt8(vp9.gof.num_frames_in_gof)); + } + for (size_t i = 0; i < vp9.gof.num_frames_in_gof; ++i) { + RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.gof.temporal_idx[i], 3)); + RETURN_FALSE_ON_ERROR( + writer->WriteBits(vp9.gof.temporal_up_switch[i] ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.gof.num_ref_pics[i], 2)); + RETURN_FALSE_ON_ERROR(writer->WriteBits(kReservedBitValue0, 2)); + for (uint8_t r = 0; r < vp9.gof.num_ref_pics[i]; ++r) { + RETURN_FALSE_ON_ERROR(writer->WriteUInt8(vp9.gof.pid_diff[i][r])); + } + } + return true; +} + +// Picture ID: +// +// +-+-+-+-+-+-+-+-+ +// I: |M| PICTURE ID | M:0 => picture id is 7 bits. +// +-+-+-+-+-+-+-+-+ M:1 => picture id is 15 bits. +// M: | EXTENDED PID | +// +-+-+-+-+-+-+-+-+ +// +bool ParsePictureId(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) { + uint32_t picture_id; + uint32_t m_bit; + RETURN_FALSE_ON_ERROR(parser->ReadBits(&m_bit, 1)); + if (m_bit) { + RETURN_FALSE_ON_ERROR(parser->ReadBits(&picture_id, 15)); + vp9->max_picture_id = kMaxTwoBytePictureId; + } else { + RETURN_FALSE_ON_ERROR(parser->ReadBits(&picture_id, 7)); + vp9->max_picture_id = kMaxOneBytePictureId; + } + vp9->picture_id = picture_id; + return true; +} + +// Layer indices (flexible mode): +// +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| +// +-+-+-+-+-+-+-+-+ +// +bool ParseLayerInfoCommon(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) { + uint32_t t, u_bit, s, d_bit; + RETURN_FALSE_ON_ERROR(parser->ReadBits(&t, 3)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&u_bit, 1)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&s, 3)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&d_bit, 1)); + vp9->temporal_idx = t; + vp9->temporal_up_switch = u_bit ? true : false; + vp9->spatial_idx = s; + vp9->inter_layer_predicted = d_bit ? true : false; + return true; +} + +// Layer indices (non-flexible mode): +// +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| +// +-+-+-+-+-+-+-+-+ +// | TL0PICIDX | +// +-+-+-+-+-+-+-+-+ +// +bool ParseLayerInfoNonFlexibleMode(rtc::BitBuffer* parser, + RTPVideoHeaderVP9* vp9) { + uint8_t tl0picidx; + RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&tl0picidx)); + vp9->tl0_pic_idx = tl0picidx; + return true; +} + +bool ParseLayerInfo(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) { + if (!ParseLayerInfoCommon(parser, vp9)) + return false; + + if (vp9->flexible_mode) + return true; + + return ParseLayerInfoNonFlexibleMode(parser, vp9); +} + +// Reference indices: +// +// +-+-+-+-+-+-+-+-+ P=1,F=1: At least one reference index +// P,F: | P_DIFF |N| up to 3 times has to be specified. +// +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows +// current P_DIFF. +// +bool ParseRefIndices(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) { + if (vp9->picture_id == kNoPictureId) + return false; + + vp9->num_ref_pics = 0; + uint32_t n_bit; + do { + if (vp9->num_ref_pics == kMaxVp9RefPics) + return false; + + uint32_t p_diff; + RETURN_FALSE_ON_ERROR(parser->ReadBits(&p_diff, 7)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&n_bit, 1)); + + vp9->pid_diff[vp9->num_ref_pics] = p_diff; + uint32_t scaled_pid = vp9->picture_id; + if (p_diff > scaled_pid) { + // TODO(asapersson): Max should correspond to the picture id of last wrap. + scaled_pid += vp9->max_picture_id + 1; + } + vp9->ref_picture_id[vp9->num_ref_pics++] = scaled_pid - p_diff; + } while (n_bit); + + return true; +} + +// Scalability structure (SS). +// +// +-+-+-+-+-+-+-+-+ +// V: | N_S |Y|G|-|-|-| +// +-+-+-+-+-+-+-+-+ -| +// Y: | WIDTH | (OPTIONAL) . +// + + . +// | | (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ . N_S + 1 times +// | HEIGHT | (OPTIONAL) . +// + + . +// | | (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ -| +// G: | N_G | (OPTIONAL) +// +-+-+-+-+-+-+-+-+ -| +// N_G: | T |U| R |-|-| (OPTIONAL) . +// +-+-+-+-+-+-+-+-+ -| . N_G times +// | P_DIFF | (OPTIONAL) . R times . +// +-+-+-+-+-+-+-+-+ -| -| +// +bool ParseSsData(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) { + uint32_t n_s, y_bit, g_bit; + RETURN_FALSE_ON_ERROR(parser->ReadBits(&n_s, 3)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&y_bit, 1)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&g_bit, 1)); + RETURN_FALSE_ON_ERROR(parser->ConsumeBits(3)); + vp9->num_spatial_layers = n_s + 1; + vp9->spatial_layer_resolution_present = y_bit ? true : false; + vp9->gof.num_frames_in_gof = 0; + + if (y_bit) { + for (size_t i = 0; i < vp9->num_spatial_layers; ++i) { + RETURN_FALSE_ON_ERROR(parser->ReadUInt16(&vp9->width[i])); + RETURN_FALSE_ON_ERROR(parser->ReadUInt16(&vp9->height[i])); + } + } + if (g_bit) { + uint8_t n_g; + RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&n_g)); + vp9->gof.num_frames_in_gof = n_g; + } + for (size_t i = 0; i < vp9->gof.num_frames_in_gof; ++i) { + uint32_t t, u_bit, r; + RETURN_FALSE_ON_ERROR(parser->ReadBits(&t, 3)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&u_bit, 1)); + RETURN_FALSE_ON_ERROR(parser->ReadBits(&r, 2)); + RETURN_FALSE_ON_ERROR(parser->ConsumeBits(2)); + vp9->gof.temporal_idx[i] = t; + vp9->gof.temporal_up_switch[i] = u_bit ? true : false; + vp9->gof.num_ref_pics[i] = r; + + for (uint8_t p = 0; p < vp9->gof.num_ref_pics[i]; ++p) { + uint8_t p_diff; + RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&p_diff)); + vp9->gof.pid_diff[i][p] = p_diff; + } + } + return true; +} +} // namespace + +RtpPacketizerVp9::RtpPacketizerVp9(const RTPVideoHeaderVP9& hdr, + size_t max_payload_length, + size_t last_packet_reduction_len) + : hdr_(hdr), + max_payload_length_(max_payload_length), + payload_(nullptr), + payload_size_(0), + last_packet_reduction_len_(last_packet_reduction_len) {} + +RtpPacketizerVp9::~RtpPacketizerVp9() { +} + +std::string RtpPacketizerVp9::ToString() { + return "RtpPacketizerVp9"; +} + +size_t RtpPacketizerVp9::SetPayloadData( + const uint8_t* payload, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) { + payload_ = payload; + payload_size_ = payload_size; + GeneratePackets(); + return packets_.size(); +} + +// Splits payload in minimal number of roughly equal in size packets. +void RtpPacketizerVp9::GeneratePackets() { + if (max_payload_length_ < PayloadDescriptorLength(hdr_) + 1) { + RTC_LOG(LS_ERROR) << "Payload header and one payload byte won't fit in the " + "first packet."; + return; + } + if (max_payload_length_ < PayloadDescriptorLengthMinusSsData(hdr_) + 1 + + last_packet_reduction_len_) { + RTC_LOG(LS_ERROR) + << "Payload header and one payload byte won't fit in the last" + " packet."; + return; + } + if (payload_size_ == 1 && + max_payload_length_ < + PayloadDescriptorLength(hdr_) + 1 + last_packet_reduction_len_) { + RTC_LOG(LS_ERROR) << "Can't fit header and payload into single packet, but " + "payload size is one: no way to generate packets with " + "nonzero payload."; + return; + } + + // Instead of making last packet smaller, we pretend that we must write + // additional data into it. We account for this virtual payload while + // calculating packets number and sizes. We also pretend that all packets + // headers are the same length and extra SS header data in the fits packet + // is also treated as a payload here. + + size_t ss_data_len = SsDataLength(hdr_); + // Payload, virtual payload and SS hdr data in the first packet together. + size_t total_bytes = ss_data_len + payload_size_ + last_packet_reduction_len_; + // Now all packets will have the same lenght of vp9 headers. + size_t per_packet_capacity = + max_payload_length_ - PayloadDescriptorLengthMinusSsData(hdr_); + // Integer division rounding up. + size_t num_packets = + (total_bytes + per_packet_capacity - 1) / per_packet_capacity; + // Average rounded down. + size_t per_packet_bytes = total_bytes / num_packets; + // Several last packets are 1 byte larger than the rest. + // i.e. if 14 bytes were split between 4 packets, it would be 3+3+4+4. + size_t num_larger_packets = total_bytes % num_packets; + size_t bytes_processed = 0; + size_t num_packets_left = num_packets; + while (bytes_processed < payload_size_) { + if (num_packets_left == num_larger_packets) + ++per_packet_bytes; + size_t packet_bytes = per_packet_bytes; + // First packet also has SS hdr data. + if (bytes_processed == 0) { + // Must write at least one byte of the real payload to the packet. + if (packet_bytes > ss_data_len) { + packet_bytes -= ss_data_len; + } else { + packet_bytes = 1; + } + } + size_t rem_bytes = payload_size_ - bytes_processed; + if (packet_bytes >= rem_bytes) { + // All remaining payload fits into this packet. + packet_bytes = rem_bytes; + // If this is the penultimate packet, leave at least 1 byte of payload for + // the last packet. + if (num_packets_left == 2) + --packet_bytes; + } + QueuePacket(bytes_processed, packet_bytes, bytes_processed == 0, + rem_bytes == packet_bytes, &packets_); + --num_packets_left; + bytes_processed += packet_bytes; + // Last packet should be smaller + RTC_DCHECK(num_packets_left > 0 || + per_packet_capacity >= + packet_bytes + last_packet_reduction_len_); + } + RTC_CHECK_EQ(bytes_processed, payload_size_); +} + +bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet) { + RTC_DCHECK(packet); + if (packets_.empty()) { + return false; + } + PacketInfo packet_info = packets_.front(); + packets_.pop(); + + if (!WriteHeaderAndPayload(packet_info, packet, packets_.empty())) { + return false; + } + packet->SetMarker(packets_.empty() && + (hdr_.spatial_idx == kNoSpatialIdx || + hdr_.spatial_idx == hdr_.num_spatial_layers - 1)); + return true; +} + +// VP9 format: +// +// Payload descriptor for F = 1 (flexible mode) +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |I|P|L|F|B|E|V|-| (REQUIRED) +// +-+-+-+-+-+-+-+-+ +// I: |M| PICTURE ID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// M: | EXTENDED PID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| (CONDITIONALLY RECOMMENDED) +// +-+-+-+-+-+-+-+-+ -| +// P,F: | P_DIFF |N| (CONDITIONALLY RECOMMENDED) . up to 3 times +// +-+-+-+-+-+-+-+-+ -| +// V: | SS | +// | .. | +// +-+-+-+-+-+-+-+-+ +// +// Payload descriptor for F = 0 (non-flexible mode) +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |I|P|L|F|B|E|V|-| (REQUIRED) +// +-+-+-+-+-+-+-+-+ +// I: |M| PICTURE ID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// M: | EXTENDED PID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| (CONDITIONALLY RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// | TL0PICIDX | (CONDITIONALLY REQUIRED) +// +-+-+-+-+-+-+-+-+ +// V: | SS | +// | .. | +// +-+-+-+-+-+-+-+-+ + +bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info, + RtpPacketToSend* packet, + bool last) const { + uint8_t* buffer = packet->AllocatePayload( + last ? max_payload_length_ - last_packet_reduction_len_ + : max_payload_length_); + RTC_DCHECK(buffer); + size_t header_length; + if (!WriteHeader(packet_info, buffer, &header_length)) + return false; + + // Copy payload data. + memcpy(&buffer[header_length], + &payload_[packet_info.payload_start_pos], packet_info.size); + + packet->SetPayloadSize(header_length + packet_info.size); + return true; +} + +bool RtpPacketizerVp9::WriteHeader(const PacketInfo& packet_info, + uint8_t* buffer, + size_t* header_length) const { + // Required payload descriptor byte. + bool i_bit = PictureIdPresent(hdr_); + bool p_bit = hdr_.inter_pic_predicted; + bool l_bit = LayerInfoPresent(hdr_); + bool f_bit = hdr_.flexible_mode; + bool b_bit = packet_info.layer_begin; + bool e_bit = packet_info.layer_end; + bool v_bit = hdr_.ss_data_available && b_bit; + + rtc::BitBufferWriter writer(buffer, max_payload_length_); + RETURN_FALSE_ON_ERROR(writer.WriteBits(i_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer.WriteBits(p_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer.WriteBits(l_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer.WriteBits(f_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer.WriteBits(b_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer.WriteBits(e_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer.WriteBits(v_bit ? 1 : 0, 1)); + RETURN_FALSE_ON_ERROR(writer.WriteBits(kReservedBitValue0, 1)); + + // Add fields that are present. + if (i_bit && !WritePictureId(hdr_, &writer)) { + RTC_LOG(LS_ERROR) << "Failed writing VP9 picture id."; + return false; + } + if (l_bit && !WriteLayerInfo(hdr_, &writer)) { + RTC_LOG(LS_ERROR) << "Failed writing VP9 layer info."; + return false; + } + if (p_bit && f_bit && !WriteRefIndices(hdr_, &writer)) { + RTC_LOG(LS_ERROR) << "Failed writing VP9 ref indices."; + return false; + } + if (v_bit && !WriteSsData(hdr_, &writer)) { + RTC_LOG(LS_ERROR) << "Failed writing VP9 SS data."; + return false; + } + + size_t offset_bytes = 0; + size_t offset_bits = 0; + writer.GetCurrentOffset(&offset_bytes, &offset_bits); + assert(offset_bits == 0); + + *header_length = offset_bytes; + return true; +} + +bool RtpDepacketizerVp9::Parse(ParsedPayload* parsed_payload, + const uint8_t* payload, + size_t payload_length) { + assert(parsed_payload != nullptr); + if (payload_length == 0) { + RTC_LOG(LS_ERROR) << "Payload length is zero."; + return false; + } + + // Parse mandatory first byte of payload descriptor. + rtc::BitBuffer parser(payload, payload_length); + uint32_t i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit; + RETURN_FALSE_ON_ERROR(parser.ReadBits(&i_bit, 1)); + RETURN_FALSE_ON_ERROR(parser.ReadBits(&p_bit, 1)); + RETURN_FALSE_ON_ERROR(parser.ReadBits(&l_bit, 1)); + RETURN_FALSE_ON_ERROR(parser.ReadBits(&f_bit, 1)); + RETURN_FALSE_ON_ERROR(parser.ReadBits(&b_bit, 1)); + RETURN_FALSE_ON_ERROR(parser.ReadBits(&e_bit, 1)); + RETURN_FALSE_ON_ERROR(parser.ReadBits(&v_bit, 1)); + RETURN_FALSE_ON_ERROR(parser.ConsumeBits(1)); + + // Parsed payload. + parsed_payload->type.Video.width = 0; + parsed_payload->type.Video.height = 0; + parsed_payload->type.Video.simulcastIdx = 0; + parsed_payload->type.Video.codec = kRtpVideoVp9; + + parsed_payload->frame_type = p_bit ? kVideoFrameDelta : kVideoFrameKey; + + RTPVideoHeaderVP9* vp9 = &parsed_payload->type.Video.codecHeader.VP9; + vp9->InitRTPVideoHeaderVP9(); + vp9->inter_pic_predicted = p_bit ? true : false; + vp9->flexible_mode = f_bit ? true : false; + vp9->beginning_of_frame = b_bit ? true : false; + vp9->end_of_frame = e_bit ? true : false; + vp9->ss_data_available = v_bit ? true : false; + + // Parse fields that are present. + if (i_bit && !ParsePictureId(&parser, vp9)) { + RTC_LOG(LS_ERROR) << "Failed parsing VP9 picture id."; + return false; + } + if (l_bit && !ParseLayerInfo(&parser, vp9)) { + RTC_LOG(LS_ERROR) << "Failed parsing VP9 layer info."; + return false; + } + if (p_bit && f_bit && !ParseRefIndices(&parser, vp9)) { + RTC_LOG(LS_ERROR) << "Failed parsing VP9 ref indices."; + return false; + } + if (v_bit) { + if (!ParseSsData(&parser, vp9)) { + RTC_LOG(LS_ERROR) << "Failed parsing VP9 SS data."; + return false; + } + if (vp9->spatial_layer_resolution_present) { + // TODO(asapersson): Add support for spatial layers. + parsed_payload->type.Video.width = vp9->width[0]; + parsed_payload->type.Video.height = vp9->height[0]; + } + } + parsed_payload->type.Video.is_first_packet_in_frame = + b_bit && (!l_bit || !vp9->inter_layer_predicted); + + uint64_t rem_bits = parser.RemainingBitCount(); + assert(rem_bits % 8 == 0); + parsed_payload->payload_length = rem_bits / 8; + if (parsed_payload->payload_length == 0) { + RTC_LOG(LS_ERROR) << "Failed parsing VP9 payload data."; + return false; + } + parsed_payload->payload = + payload + payload_length - parsed_payload->payload_length; + + return true; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h new file mode 100644 index 0000000000..aa86ccdfa4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h @@ -0,0 +1,101 @@ +/* + * 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. + */ + +// +// This file contains the declaration of the VP9 packetizer class. +// A packetizer object is created for each encoded video frame. The +// constructor is called with the payload data and size. +// +// After creating the packetizer, the method NextPacket is called +// repeatedly to get all packets for the frame. The method returns +// false as long as there are more packets left to fetch. +// + +#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP9_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP9_H_ + +#include <queue> +#include <string> + +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "rtc_base/constructormagic.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class RtpPacketizerVp9 : public RtpPacketizer { + public: + RtpPacketizerVp9(const RTPVideoHeaderVP9& hdr, + size_t max_payload_length, + size_t last_packet_reduction_len); + + virtual ~RtpPacketizerVp9(); + + std::string ToString() override; + + // The payload data must be one encoded VP9 layer frame. + size_t SetPayloadData(const uint8_t* payload, + size_t payload_size, + const RTPFragmentationHeader* fragmentation) override; + + // Gets the next payload with VP9 payload header. + // Write payload and set marker bit of the |packet|. + // Returns true on success, false otherwise. + bool NextPacket(RtpPacketToSend* packet) override; + + typedef struct { + size_t payload_start_pos; + size_t size; + bool layer_begin; + bool layer_end; + } PacketInfo; + typedef std::queue<PacketInfo> PacketInfoQueue; + + private: + // Calculates all packet sizes and loads info to packet queue. + void GeneratePackets(); + + // Writes the payload descriptor header and copies payload to the |buffer|. + // |packet_info| determines which part of the payload to write. + // |last| indicates if the packet is the last packet in the frame. + // Returns true on success, false otherwise. + bool WriteHeaderAndPayload(const PacketInfo& packet_info, + RtpPacketToSend* packet, + bool last) const; + + // Writes payload descriptor header to |buffer|. + // Returns true on success, false otherwise. + bool WriteHeader(const PacketInfo& packet_info, + uint8_t* buffer, + size_t* header_length) const; + + const RTPVideoHeaderVP9 hdr_; + const size_t max_payload_length_; // The max length in bytes of one packet. + const uint8_t* payload_; // The payload data to be packetized. + size_t payload_size_; // The size in bytes of the payload data. + const size_t last_packet_reduction_len_; + PacketInfoQueue packets_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp9); +}; + + +class RtpDepacketizerVp9 : public RtpDepacketizer { + public: + virtual ~RtpDepacketizerVp9() {} + + bool Parse(ParsedPayload* parsed_payload, + const uint8_t* payload, + size_t payload_length) override; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP9_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc new file mode 100644 index 0000000000..c522c4dc8a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc @@ -0,0 +1,810 @@ +/* + * 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. + */ + +#include <memory> +#include <vector> + +#include "modules/rtp_rtcp/source/rtp_format_vp9.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +namespace { +void VerifyHeader(const RTPVideoHeaderVP9& expected, + const RTPVideoHeaderVP9& actual) { + EXPECT_EQ(expected.inter_layer_predicted, actual.inter_layer_predicted); + EXPECT_EQ(expected.inter_pic_predicted, actual.inter_pic_predicted); + EXPECT_EQ(expected.flexible_mode, actual.flexible_mode); + EXPECT_EQ(expected.beginning_of_frame, actual.beginning_of_frame); + EXPECT_EQ(expected.end_of_frame, actual.end_of_frame); + EXPECT_EQ(expected.ss_data_available, actual.ss_data_available); + EXPECT_EQ(expected.picture_id, actual.picture_id); + EXPECT_EQ(expected.max_picture_id, actual.max_picture_id); + EXPECT_EQ(expected.temporal_idx, actual.temporal_idx); + EXPECT_EQ(expected.spatial_idx, actual.spatial_idx); + EXPECT_EQ(expected.gof_idx, actual.gof_idx); + EXPECT_EQ(expected.tl0_pic_idx, actual.tl0_pic_idx); + EXPECT_EQ(expected.temporal_up_switch, actual.temporal_up_switch); + + EXPECT_EQ(expected.num_ref_pics, actual.num_ref_pics); + for (uint8_t i = 0; i < expected.num_ref_pics; ++i) { + EXPECT_EQ(expected.pid_diff[i], actual.pid_diff[i]); + EXPECT_EQ(expected.ref_picture_id[i], actual.ref_picture_id[i]); + } + if (expected.ss_data_available) { + EXPECT_EQ(expected.spatial_layer_resolution_present, + actual.spatial_layer_resolution_present); + EXPECT_EQ(expected.num_spatial_layers, actual.num_spatial_layers); + if (expected.spatial_layer_resolution_present) { + for (size_t i = 0; i < expected.num_spatial_layers; i++) { + EXPECT_EQ(expected.width[i], actual.width[i]); + EXPECT_EQ(expected.height[i], actual.height[i]); + } + } + EXPECT_EQ(expected.gof.num_frames_in_gof, actual.gof.num_frames_in_gof); + for (size_t i = 0; i < expected.gof.num_frames_in_gof; i++) { + EXPECT_EQ(expected.gof.temporal_up_switch[i], + actual.gof.temporal_up_switch[i]); + EXPECT_EQ(expected.gof.temporal_idx[i], actual.gof.temporal_idx[i]); + EXPECT_EQ(expected.gof.num_ref_pics[i], actual.gof.num_ref_pics[i]); + for (uint8_t j = 0; j < expected.gof.num_ref_pics[i]; j++) { + EXPECT_EQ(expected.gof.pid_diff[i][j], actual.gof.pid_diff[i][j]); + } + } + } +} + +void VerifyPayload(const RtpDepacketizer::ParsedPayload& parsed, + const uint8_t* payload, + size_t payload_length) { + EXPECT_EQ(payload, parsed.payload); + EXPECT_EQ(payload_length, parsed.payload_length); + EXPECT_THAT(std::vector<uint8_t>(parsed.payload, + parsed.payload + parsed.payload_length), + ::testing::ElementsAreArray(payload, payload_length)); +} + +void ParseAndCheckPacket(const uint8_t* packet, + const RTPVideoHeaderVP9& expected, + size_t expected_hdr_length, + size_t expected_length) { + std::unique_ptr<RtpDepacketizer> depacketizer(new RtpDepacketizerVp9()); + RtpDepacketizer::ParsedPayload parsed; + ASSERT_TRUE(depacketizer->Parse(&parsed, packet, expected_length)); + EXPECT_EQ(kRtpVideoVp9, parsed.type.Video.codec); + VerifyHeader(expected, parsed.type.Video.codecHeader.VP9); + const size_t kExpectedPayloadLength = expected_length - expected_hdr_length; + VerifyPayload(parsed, packet + expected_hdr_length, kExpectedPayloadLength); +} +} // namespace + +// Payload descriptor for flexible mode +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |I|P|L|F|B|E|V|-| (REQUIRED) +// +-+-+-+-+-+-+-+-+ +// I: |M| PICTURE ID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// M: | EXTENDED PID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| (CONDITIONALLY RECOMMENDED) +// +-+-+-+-+-+-+-+-+ -| +// P,F: | P_DIFF |N| (CONDITIONALLY RECOMMENDED) . up to 3 times +// +-+-+-+-+-+-+-+-+ -| +// V: | SS | +// | .. | +// +-+-+-+-+-+-+-+-+ +// +// Payload descriptor for non-flexible mode +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |I|P|L|F|B|E|V|-| (REQUIRED) +// +-+-+-+-+-+-+-+-+ +// I: |M| PICTURE ID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// M: | EXTENDED PID | (RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// L: | T |U| S |D| (CONDITIONALLY RECOMMENDED) +// +-+-+-+-+-+-+-+-+ +// | TL0PICIDX | (CONDITIONALLY REQUIRED) +// +-+-+-+-+-+-+-+-+ +// V: | SS | +// | .. | +// +-+-+-+-+-+-+-+-+ + +class RtpPacketizerVp9Test : public ::testing::Test { + protected: + static constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; + static constexpr size_t kMaxPacketSize = 1200; + + RtpPacketizerVp9Test() : packet_(kNoExtensions, kMaxPacketSize) {} + virtual void SetUp() { + expected_.InitRTPVideoHeaderVP9(); + } + + RtpPacketToSend packet_; + std::unique_ptr<uint8_t[]> payload_; + size_t payload_size_; + size_t payload_pos_; + RTPVideoHeaderVP9 expected_; + std::unique_ptr<RtpPacketizerVp9> packetizer_; + size_t num_packets_; + + void Init(size_t payload_size, size_t packet_size) { + payload_.reset(new uint8_t[payload_size]); + memset(payload_.get(), 7, payload_size); + payload_size_ = payload_size; + payload_pos_ = 0; + packetizer_.reset(new RtpPacketizerVp9(expected_, packet_size, + /*last_packet_reduction_len=*/0)); + num_packets_ = + packetizer_->SetPayloadData(payload_.get(), payload_size_, nullptr); + } + + void CheckPayload(const uint8_t* packet, + size_t start_pos, + size_t end_pos, + bool last) { + for (size_t i = start_pos; i < end_pos; ++i) { + EXPECT_EQ(packet[i], payload_[payload_pos_++]); + } + EXPECT_EQ(last, payload_pos_ == payload_size_); + } + + void CreateParseAndCheckPackets(const size_t* expected_hdr_sizes, + const size_t* expected_sizes, + size_t expected_num_packets) { + ASSERT_TRUE(packetizer_.get() != NULL); + if (expected_num_packets == 0) { + EXPECT_FALSE(packetizer_->NextPacket(&packet_)); + return; + } + EXPECT_EQ(expected_num_packets, num_packets_); + for (size_t i = 0; i < expected_num_packets; ++i) { + EXPECT_TRUE(packetizer_->NextPacket(&packet_)); + auto rtp_payload = packet_.payload(); + EXPECT_EQ(expected_sizes[i], rtp_payload.size()); + RTPVideoHeaderVP9 hdr = expected_; + hdr.beginning_of_frame = (i == 0); + hdr.end_of_frame = (i + 1) == expected_num_packets; + ParseAndCheckPacket(rtp_payload.data(), hdr, expected_hdr_sizes[i], + rtp_payload.size()); + CheckPayload(rtp_payload.data(), expected_hdr_sizes[i], + rtp_payload.size(), (i + 1) == expected_num_packets); + expected_.ss_data_available = false; + } + } +}; + +TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_OnePacket) { + const size_t kFrameSize = 25; + const size_t kPacketSize = 26; + Init(kFrameSize, kPacketSize); + + // One packet: + // I:0, P:0, L:0, F:0, B:1, E:1, V:0 (1hdr + 25 payload) + const size_t kExpectedHdrSizes[] = {1}; + const size_t kExpectedSizes[] = {26}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_TwoPackets) { + const size_t kFrameSize = 27; + const size_t kPacketSize = 27; + Init(kFrameSize, kPacketSize); + + // Two packets: + // I:0, P:0, L:0, F:0, B:1, E:0, V:0 (1hdr + 14 payload) + // I:0, P:0, L:0, F:0, B:0, E:1, V:0 (1hdr + 13 payload) + const size_t kExpectedHdrSizes[] = {1, 1}; + const size_t kExpectedSizes[] = {14, 15}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestTooShortBufferToFitPayload) { + const size_t kFrameSize = 1; + const size_t kPacketSize = 1; + Init(kFrameSize, kPacketSize); // 1hdr + 1 payload + + const size_t kExpectedNum = 0; + CreateParseAndCheckPackets(NULL, NULL, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestOneBytePictureId) { + const size_t kFrameSize = 30; + const size_t kPacketSize = 12; + + expected_.picture_id = kMaxOneBytePictureId; // 2 byte payload descriptor + expected_.max_picture_id = kMaxOneBytePictureId; + Init(kFrameSize, kPacketSize); + + // Three packets: + // I:1, P:0, L:0, F:0, B:1, E:0, V:0 (2hdr + 10 payload) + // I:1, P:0, L:0, F:0, B:0, E:0, V:0 (2hdr + 10 payload) + // I:1, P:0, L:0, F:0, B:0, E:1, V:0 (2hdr + 10 payload) + const size_t kExpectedHdrSizes[] = {2, 2, 2}; + const size_t kExpectedSizes[] = {12, 12, 12}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestTwoBytePictureId) { + const size_t kFrameSize = 31; + const size_t kPacketSize = 13; + + expected_.picture_id = kMaxTwoBytePictureId; // 3 byte payload descriptor + Init(kFrameSize, kPacketSize); + + // Four packets: + // I:1, P:0, L:0, F:0, B:1, E:0, V:0 (3hdr + 8 payload) + // I:1, P:0, L:0, F:0, B:0, E:0, V:0 (3hdr + 8 payload) + // I:1, P:0, L:0, F:0, B:0, E:0, V:0 (3hdr + 8 payload) + // I:1, P:0, L:0, F:0, B:0, E:1, V:0 (3hdr + 7 payload) + const size_t kExpectedHdrSizes[] = {3, 3, 3, 3}; + const size_t kExpectedSizes[] = {10, 11, 11, 11}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestLayerInfoWithNonFlexibleMode) { + const size_t kFrameSize = 30; + const size_t kPacketSize = 25; + + expected_.temporal_idx = 3; + expected_.temporal_up_switch = true; // U + expected_.num_spatial_layers = 3; + expected_.spatial_idx = 2; + expected_.inter_layer_predicted = true; // D + expected_.tl0_pic_idx = 117; + Init(kFrameSize, kPacketSize); + + // Two packets: + // | I:0, P:0, L:1, F:0, B:1, E:0, V:0 | (3hdr + 15 payload) + // L: | T:3, U:1, S:2, D:1 | TL0PICIDX:117 | + // | I:0, P:0, L:1, F:0, B:0, E:1, V:0 | (3hdr + 15 payload) + // L: | T:3, U:1, S:2, D:1 | TL0PICIDX:117 | + const size_t kExpectedHdrSizes[] = {3, 3}; + const size_t kExpectedSizes[] = {18, 18}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestLayerInfoWithFlexibleMode) { + const size_t kFrameSize = 21; + const size_t kPacketSize = 23; + + expected_.flexible_mode = true; + expected_.temporal_idx = 3; + expected_.temporal_up_switch = true; // U + expected_.num_spatial_layers = 3; + expected_.spatial_idx = 2; + expected_.inter_layer_predicted = false; // D + Init(kFrameSize, kPacketSize); + + // One packet: + // I:0, P:0, L:1, F:1, B:1, E:1, V:0 (2hdr + 21 payload) + // L: T:3, U:1, S:2, D:0 + const size_t kExpectedHdrSizes[] = {2}; + const size_t kExpectedSizes[] = {23}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestRefIdx) { + const size_t kFrameSize = 16; + const size_t kPacketSize = 21; + + expected_.inter_pic_predicted = true; // P + expected_.flexible_mode = true; // F + expected_.picture_id = 2; + expected_.max_picture_id = kMaxOneBytePictureId; + + expected_.num_ref_pics = 3; + expected_.pid_diff[0] = 1; + expected_.pid_diff[1] = 3; + expected_.pid_diff[2] = 127; + expected_.ref_picture_id[0] = 1; // 2 - 1 = 1 + expected_.ref_picture_id[1] = 127; // (kMaxPictureId + 1) + 2 - 3 = 127 + expected_.ref_picture_id[2] = 3; // (kMaxPictureId + 1) + 2 - 127 = 3 + Init(kFrameSize, kPacketSize); + + // Two packets: + // I:1, P:1, L:0, F:1, B:1, E:1, V:0 (5hdr + 16 payload) + // I: 2 + // P,F: P_DIFF:1, N:1 + // P_DIFF:3, N:1 + // P_DIFF:127, N:0 + const size_t kExpectedHdrSizes[] = {5}; + const size_t kExpectedSizes[] = {21}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestRefIdxFailsWithoutPictureId) { + const size_t kFrameSize = 16; + const size_t kPacketSize = 21; + + expected_.inter_pic_predicted = true; + expected_.flexible_mode = true; + expected_.num_ref_pics = 1; + expected_.pid_diff[0] = 3; + Init(kFrameSize, kPacketSize); + + const size_t kExpectedNum = 0; + CreateParseAndCheckPackets(NULL, NULL, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestSsDataWithoutSpatialResolutionPresent) { + const size_t kFrameSize = 21; + const size_t kPacketSize = 26; + + expected_.ss_data_available = true; + expected_.num_spatial_layers = 1; + expected_.spatial_layer_resolution_present = false; + expected_.gof.num_frames_in_gof = 1; + expected_.gof.temporal_idx[0] = 0; + expected_.gof.temporal_up_switch[0] = true; + expected_.gof.num_ref_pics[0] = 1; + expected_.gof.pid_diff[0][0] = 4; + Init(kFrameSize, kPacketSize); + + // One packet: + // I:0, P:0, L:0, F:0, B:1, E:1, V:1 (5hdr + 21 payload) + // N_S:0, Y:0, G:1 + // N_G:1 + // T:0, U:1, R:1 | P_DIFF[0][0]:4 + const size_t kExpectedHdrSizes[] = {5}; + const size_t kExpectedSizes[] = {26}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestSsDataWithoutGbitPresent) { + const size_t kFrameSize = 21; + const size_t kPacketSize = 23; + + expected_.ss_data_available = true; + expected_.num_spatial_layers = 1; + expected_.spatial_layer_resolution_present = false; + expected_.gof.num_frames_in_gof = 0; + Init(kFrameSize, kPacketSize); + + // One packet: + // I:0, P:0, L:0, F:0, B:1, E:1, V:1 (2hdr + 21 payload) + // N_S:0, Y:0, G:0 + const size_t kExpectedHdrSizes[] = {2}; + const size_t kExpectedSizes[] = {23}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestSsData) { + const size_t kFrameSize = 21; + const size_t kPacketSize = 40; + + expected_.ss_data_available = true; + expected_.num_spatial_layers = 2; + expected_.spatial_layer_resolution_present = true; + expected_.width[0] = 640; + expected_.width[1] = 1280; + expected_.height[0] = 360; + expected_.height[1] = 720; + expected_.gof.num_frames_in_gof = 3; + expected_.gof.temporal_idx[0] = 0; + expected_.gof.temporal_idx[1] = 1; + expected_.gof.temporal_idx[2] = 2; + expected_.gof.temporal_up_switch[0] = true; + expected_.gof.temporal_up_switch[1] = true; + expected_.gof.temporal_up_switch[2] = false; + expected_.gof.num_ref_pics[0] = 0; + expected_.gof.num_ref_pics[1] = 3; + expected_.gof.num_ref_pics[2] = 2; + expected_.gof.pid_diff[1][0] = 5; + expected_.gof.pid_diff[1][1] = 6; + expected_.gof.pid_diff[1][2] = 7; + expected_.gof.pid_diff[2][0] = 8; + expected_.gof.pid_diff[2][1] = 9; + Init(kFrameSize, kPacketSize); + + // One packet: + // I:0, P:0, L:0, F:0, B:1, E:1, V:1 (19hdr + 21 payload) + // N_S:1, Y:1, G:1 + // WIDTH:640 // 2 bytes + // HEIGHT:360 // 2 bytes + // WIDTH:1280 // 2 bytes + // HEIGHT:720 // 2 bytes + // N_G:3 + // T:0, U:1, R:0 + // T:1, U:1, R:3 | P_DIFF[1][0]:5 | P_DIFF[1][1]:6 | P_DIFF[1][2]:7 + // T:2, U:0, R:2 | P_DIFF[2][0]:8 | P_DIFF[2][0]:9 + const size_t kExpectedHdrSizes[] = {19}; + const size_t kExpectedSizes[] = {40}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestSsDataDoesNotFitInAveragePacket) { + const size_t kFrameSize = 24; + const size_t kPacketSize = 20; + + expected_.ss_data_available = true; + expected_.num_spatial_layers = 2; + expected_.spatial_layer_resolution_present = true; + expected_.width[0] = 640; + expected_.width[1] = 1280; + expected_.height[0] = 360; + expected_.height[1] = 720; + expected_.gof.num_frames_in_gof = 3; + expected_.gof.temporal_idx[0] = 0; + expected_.gof.temporal_idx[1] = 1; + expected_.gof.temporal_idx[2] = 2; + expected_.gof.temporal_up_switch[0] = true; + expected_.gof.temporal_up_switch[1] = true; + expected_.gof.temporal_up_switch[2] = false; + expected_.gof.num_ref_pics[0] = 0; + expected_.gof.num_ref_pics[1] = 3; + expected_.gof.num_ref_pics[2] = 2; + expected_.gof.pid_diff[1][0] = 5; + expected_.gof.pid_diff[1][1] = 6; + expected_.gof.pid_diff[1][2] = 7; + expected_.gof.pid_diff[2][0] = 8; + expected_.gof.pid_diff[2][1] = 9; + Init(kFrameSize, kPacketSize); + + // Three packets: + // I:0, P:0, L:0, F:0, B:1, E:1, V:1 (19hdr + 1 payload) + // N_S:1, Y:1, G:1 + // WIDTH:640 // 2 bytes + // HEIGHT:360 // 2 bytes + // WIDTH:1280 // 2 bytes + // HEIGHT:720 // 2 bytes + // N_G:3 + // T:0, U:1, R:0 + // T:1, U:1, R:3 | P_DIFF[1][0]:5 | P_DIFF[1][1]:6 | P_DIFF[1][2]:7 + // T:2, U:0, R:2 | P_DIFF[2][0]:8 | P_DIFF[2][0]:9 + // Last two packets 1 bytes vp9 hdrs and the rest of payload 14 and 9 bytes. + const size_t kExpectedHdrSizes[] = {19, 1, 1}; + const size_t kExpectedSizes[] = {20, 15, 10}; + const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes); + CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum); +} + +TEST_F(RtpPacketizerVp9Test, TestOnlyHighestSpatialLayerSetMarker) { + const size_t kFrameSize = 10; + const size_t kPacketSize = 8; + const size_t kLastPacketReductionLen = 0; + const uint8_t kFrame[kFrameSize] = {7}; + const RTPFragmentationHeader* kNoFragmentation = nullptr; + + RTPVideoHeaderVP9 vp9_header; + vp9_header.InitRTPVideoHeaderVP9(); + vp9_header.flexible_mode = true; + vp9_header.num_spatial_layers = 3; + + RtpPacketToSend packet(kNoExtensions); + + vp9_header.spatial_idx = 0; + RtpPacketizerVp9 packetizer0(vp9_header, kPacketSize, + kLastPacketReductionLen); + packetizer0.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation); + ASSERT_TRUE(packetizer0.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer0.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + + vp9_header.spatial_idx = 1; + RtpPacketizerVp9 packetizer1(vp9_header, kPacketSize, + kLastPacketReductionLen); + packetizer1.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation); + ASSERT_TRUE(packetizer1.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer1.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + + vp9_header.spatial_idx = 2; + RtpPacketizerVp9 packetizer2(vp9_header, kPacketSize, + kLastPacketReductionLen); + packetizer2.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation); + ASSERT_TRUE(packetizer2.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer2.NextPacket(&packet)); + EXPECT_TRUE(packet.Marker()); +} + +TEST_F(RtpPacketizerVp9Test, TestGeneratesMinimumNumberOfPackets) { + const size_t kFrameSize = 10; + const size_t kPacketSize = 8; + const size_t kLastPacketReductionLen = 0; + // Calculated by hand. One packet can contain + // |kPacketSize| - |kVp9MinDiscriptorSize| = 6 bytes of the frame payload, + // thus to fit 10 bytes two packets are required. + const size_t kMinNumberOfPackets = 2; + const uint8_t kFrame[kFrameSize] = {7}; + const RTPFragmentationHeader* kNoFragmentation = nullptr; + + RTPVideoHeaderVP9 vp9_header; + vp9_header.InitRTPVideoHeaderVP9(); + + RtpPacketToSend packet(kNoExtensions); + + RtpPacketizerVp9 packetizer(vp9_header, kPacketSize, kLastPacketReductionLen); + EXPECT_EQ(kMinNumberOfPackets, packetizer.SetPayloadData( + kFrame, sizeof(kFrame), kNoFragmentation)); + ASSERT_TRUE(packetizer.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer.NextPacket(&packet)); + EXPECT_TRUE(packet.Marker()); +} + +TEST_F(RtpPacketizerVp9Test, TestRespectsLastPacketReductionLen) { + const size_t kFrameSize = 10; + const size_t kPacketSize = 8; + const size_t kLastPacketReductionLen = 5; + // Calculated by hand. VP9 payload descriptor is 2 bytes. Like in the test + // above, 1 packet is not enough. 2 packets can contain + // 2*(|kPacketSize| - |kVp9MinDiscriptorSize|) - |kLastPacketReductionLen| = 7 + // But three packets are enough, since they have capacity of 3*(8-2)-5=13 + // bytes. + const size_t kMinNumberOfPackets = 3; + const uint8_t kFrame[kFrameSize] = {7}; + const RTPFragmentationHeader* kNoFragmentation = nullptr; + + RTPVideoHeaderVP9 vp9_header; + vp9_header.InitRTPVideoHeaderVP9(); + vp9_header.flexible_mode = true; + + RtpPacketToSend packet(kNoExtensions); + + RtpPacketizerVp9 packetizer0(vp9_header, kPacketSize, + kLastPacketReductionLen); + EXPECT_EQ( + packetizer0.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation), + kMinNumberOfPackets); + ASSERT_TRUE(packetizer0.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer0.NextPacket(&packet)); + EXPECT_FALSE(packet.Marker()); + ASSERT_TRUE(packetizer0.NextPacket(&packet)); + EXPECT_TRUE(packet.Marker()); +} + +class RtpDepacketizerVp9Test : public ::testing::Test { + protected: + RtpDepacketizerVp9Test() + : depacketizer_(new RtpDepacketizerVp9()) {} + + virtual void SetUp() { + expected_.InitRTPVideoHeaderVP9(); + } + + RTPVideoHeaderVP9 expected_; + std::unique_ptr<RtpDepacketizer> depacketizer_; +}; + +TEST_F(RtpDepacketizerVp9Test, ParseBasicHeader) { + const uint8_t kHeaderLength = 1; + uint8_t packet[4] = {0}; + packet[0] = 0x0C; // I:0 P:0 L:0 F:0 B:1 E:1 V:0 R:0 + expected_.beginning_of_frame = true; + expected_.end_of_frame = true; + ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseOneBytePictureId) { + const uint8_t kHeaderLength = 2; + uint8_t packet[10] = {0}; + packet[0] = 0x80; // I:1 P:0 L:0 F:0 B:0 E:0 V:0 R:0 + packet[1] = kMaxOneBytePictureId; + + expected_.picture_id = kMaxOneBytePictureId; + expected_.max_picture_id = kMaxOneBytePictureId; + ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseTwoBytePictureId) { + const uint8_t kHeaderLength = 3; + uint8_t packet[10] = {0}; + packet[0] = 0x80; // I:1 P:0 L:0 F:0 B:0 E:0 V:0 R:0 + packet[1] = 0x80 | ((kMaxTwoBytePictureId >> 8) & 0x7F); + packet[2] = kMaxTwoBytePictureId & 0xFF; + + expected_.picture_id = kMaxTwoBytePictureId; + expected_.max_picture_id = kMaxTwoBytePictureId; + ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseLayerInfoWithNonFlexibleMode) { + const uint8_t kHeaderLength = 3; + const uint8_t kTemporalIdx = 2; + const uint8_t kUbit = 1; + const uint8_t kSpatialIdx = 1; + const uint8_t kDbit = 1; + const uint8_t kTl0PicIdx = 17; + uint8_t packet[13] = {0}; + packet[0] = 0x20; // I:0 P:0 L:1 F:0 B:0 E:0 V:0 R:0 + packet[1] = (kTemporalIdx << 5) | (kUbit << 4) | (kSpatialIdx << 1) | kDbit; + packet[2] = kTl0PicIdx; + + // T:2 U:1 S:1 D:1 + // TL0PICIDX:17 + expected_.temporal_idx = kTemporalIdx; + expected_.temporal_up_switch = kUbit ? true : false; + expected_.spatial_idx = kSpatialIdx; + expected_.inter_layer_predicted = kDbit ? true : false; + expected_.tl0_pic_idx = kTl0PicIdx; + ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseLayerInfoWithFlexibleMode) { + const uint8_t kHeaderLength = 2; + const uint8_t kTemporalIdx = 2; + const uint8_t kUbit = 1; + const uint8_t kSpatialIdx = 0; + const uint8_t kDbit = 0; + uint8_t packet[13] = {0}; + packet[0] = 0x38; // I:0 P:0 L:1 F:1 B:1 E:0 V:0 R:0 + packet[1] = (kTemporalIdx << 5) | (kUbit << 4) | (kSpatialIdx << 1) | kDbit; + + // I:0 P:0 L:1 F:1 B:1 E:0 V:0 + // L: T:2 U:1 S:0 D:0 + expected_.beginning_of_frame = true; + expected_.flexible_mode = true; + expected_.temporal_idx = kTemporalIdx; + expected_.temporal_up_switch = kUbit ? true : false; + expected_.spatial_idx = kSpatialIdx; + expected_.inter_layer_predicted = kDbit ? true : false; + ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseRefIdx) { + const uint8_t kHeaderLength = 6; + const int16_t kPictureId = 17; + const uint8_t kPdiff1 = 17; + const uint8_t kPdiff2 = 18; + const uint8_t kPdiff3 = 127; + uint8_t packet[13] = {0}; + packet[0] = 0xD8; // I:1 P:1 L:0 F:1 B:1 E:0 V:0 R:0 + packet[1] = 0x80 | ((kPictureId >> 8) & 0x7F); // Two byte pictureID. + packet[2] = kPictureId; + packet[3] = (kPdiff1 << 1) | 1; // P_DIFF N:1 + packet[4] = (kPdiff2 << 1) | 1; // P_DIFF N:1 + packet[5] = (kPdiff3 << 1) | 0; // P_DIFF N:0 + + // I:1 P:1 L:0 F:1 B:1 E:0 V:0 + // I: PICTURE ID:17 + // I: + // P,F: P_DIFF:17 N:1 => refPicId = 17 - 17 = 0 + // P,F: P_DIFF:18 N:1 => refPicId = (kMaxPictureId + 1) + 17 - 18 = 0x7FFF + // P,F: P_DIFF:127 N:0 => refPicId = (kMaxPictureId + 1) + 17 - 127 = 32658 + expected_.beginning_of_frame = true; + expected_.inter_pic_predicted = true; + expected_.flexible_mode = true; + expected_.picture_id = kPictureId; + expected_.num_ref_pics = 3; + expected_.pid_diff[0] = kPdiff1; + expected_.pid_diff[1] = kPdiff2; + expected_.pid_diff[2] = kPdiff3; + expected_.ref_picture_id[0] = 0; + expected_.ref_picture_id[1] = 0x7FFF; + expected_.ref_picture_id[2] = 32658; + ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseRefIdxFailsWithNoPictureId) { + const uint8_t kPdiff = 3; + uint8_t packet[13] = {0}; + packet[0] = 0x58; // I:0 P:1 L:0 F:1 B:1 E:0 V:0 R:0 + packet[1] = (kPdiff << 1); // P,F: P_DIFF:3 N:0 + + RtpDepacketizer::ParsedPayload parsed; + EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet))); +} + +TEST_F(RtpDepacketizerVp9Test, ParseRefIdxFailsWithTooManyRefPics) { + const uint8_t kPdiff = 3; + uint8_t packet[13] = {0}; + packet[0] = 0xD8; // I:1 P:1 L:0 F:1 B:1 E:0 V:0 R:0 + packet[1] = kMaxOneBytePictureId; // I: PICTURE ID:127 + packet[2] = (kPdiff << 1) | 1; // P,F: P_DIFF:3 N:1 + packet[3] = (kPdiff << 1) | 1; // P,F: P_DIFF:3 N:1 + packet[4] = (kPdiff << 1) | 1; // P,F: P_DIFF:3 N:1 + packet[5] = (kPdiff << 1) | 0; // P,F: P_DIFF:3 N:0 + + RtpDepacketizer::ParsedPayload parsed; + EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet))); +} + +TEST_F(RtpDepacketizerVp9Test, ParseSsData) { + const uint8_t kHeaderLength = 6; + const uint8_t kYbit = 0; + const size_t kNs = 2; + const size_t kNg = 2; + uint8_t packet[23] = {0}; + packet[0] = 0x0A; // I:0 P:0 L:0 F:0 B:1 E:0 V:1 R:0 + packet[1] = ((kNs - 1) << 5) | (kYbit << 4) | (1 << 3); // N_S Y G:1 - + packet[2] = kNg; // N_G + packet[3] = (0 << 5) | (1 << 4) | (0 << 2) | 0; // T:0 U:1 R:0 - + packet[4] = (2 << 5) | (0 << 4) | (1 << 2) | 0; // T:2 U:0 R:1 - + packet[5] = 33; + + expected_.beginning_of_frame = true; + expected_.ss_data_available = true; + expected_.num_spatial_layers = kNs; + expected_.spatial_layer_resolution_present = kYbit ? true : false; + expected_.gof.num_frames_in_gof = kNg; + expected_.gof.temporal_idx[0] = 0; + expected_.gof.temporal_idx[1] = 2; + expected_.gof.temporal_up_switch[0] = true; + expected_.gof.temporal_up_switch[1] = false; + expected_.gof.num_ref_pics[0] = 0; + expected_.gof.num_ref_pics[1] = 1; + expected_.gof.pid_diff[1][0] = 33; + ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseFirstPacketInKeyFrame) { + uint8_t packet[2] = {0}; + packet[0] = 0x08; // I:0 P:0 L:0 F:0 B:1 E:0 V:0 R:0 + + RtpDepacketizer::ParsedPayload parsed; + ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet))); + EXPECT_EQ(kVideoFrameKey, parsed.frame_type); + EXPECT_TRUE(parsed.type.Video.is_first_packet_in_frame); +} + +TEST_F(RtpDepacketizerVp9Test, ParseLastPacketInDeltaFrame) { + uint8_t packet[2] = {0}; + packet[0] = 0x44; // I:0 P:1 L:0 F:0 B:0 E:1 V:0 R:0 + + RtpDepacketizer::ParsedPayload parsed; + ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet))); + EXPECT_EQ(kVideoFrameDelta, parsed.frame_type); + EXPECT_FALSE(parsed.type.Video.is_first_packet_in_frame); +} + +TEST_F(RtpDepacketizerVp9Test, ParseResolution) { + const uint16_t kWidth[2] = {640, 1280}; + const uint16_t kHeight[2] = {360, 720}; + uint8_t packet[20] = {0}; + packet[0] = 0x0A; // I:0 P:0 L:0 F:0 B:1 E:0 V:1 R:0 + packet[1] = (1 << 5) | (1 << 4) | 0; // N_S:1 Y:1 G:0 + packet[2] = kWidth[0] >> 8; + packet[3] = kWidth[0] & 0xFF; + packet[4] = kHeight[0] >> 8; + packet[5] = kHeight[0] & 0xFF; + packet[6] = kWidth[1] >> 8; + packet[7] = kWidth[1] & 0xFF; + packet[8] = kHeight[1] >> 8; + packet[9] = kHeight[1] & 0xFF; + + RtpDepacketizer::ParsedPayload parsed; + ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet))); + EXPECT_EQ(kWidth[0], parsed.type.Video.width); + EXPECT_EQ(kHeight[0], parsed.type.Video.height); +} + +TEST_F(RtpDepacketizerVp9Test, ParseFailsForNoPayloadLength) { + uint8_t packet[1] = {0}; + RtpDepacketizer::ParsedPayload parsed; + EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, 0)); +} + +TEST_F(RtpDepacketizerVp9Test, ParseFailsForTooShortBufferToFitPayload) { + const uint8_t kHeaderLength = 1; + uint8_t packet[kHeaderLength] = {0}; + RtpDepacketizer::ParsedPayload parsed; + EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet))); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc new file mode 100644 index 0000000000..70f458fc98 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc @@ -0,0 +1,151 @@ +/* + * 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 "modules/rtp_rtcp/include/rtp_header_extension_map.h" + +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { + +struct ExtensionInfo { + RTPExtensionType type; + const char* uri; +}; + +template <typename Extension> +constexpr ExtensionInfo CreateExtensionInfo() { + return {Extension::kId, Extension::kUri}; +} + +constexpr ExtensionInfo kExtensions[] = { + CreateExtensionInfo<TransmissionOffset>(), + CreateExtensionInfo<AudioLevel>(), + CreateExtensionInfo<AbsoluteSendTime>(), + CreateExtensionInfo<VideoOrientation>(), + CreateExtensionInfo<TransportSequenceNumber>(), + CreateExtensionInfo<PlayoutDelayLimits>(), + CreateExtensionInfo<VideoContentTypeExtension>(), + CreateExtensionInfo<VideoTimingExtension>(), + CreateExtensionInfo<RtpStreamId>(), + CreateExtensionInfo<RepairedRtpStreamId>(), + CreateExtensionInfo<RtpMid>(), + CreateExtensionInfo<CsrcAudioLevel>(), +}; + +// Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual +// number of known extensions. +static_assert(arraysize(kExtensions) == + static_cast<int>(kRtpExtensionNumberOfExtensions) - 1, + "kExtensions expect to list all known extensions"); + +} // namespace + +constexpr RTPExtensionType RtpHeaderExtensionMap::kInvalidType; +constexpr int RtpHeaderExtensionMap::kInvalidId; +constexpr int RtpHeaderExtensionMap::kMinId; +constexpr int RtpHeaderExtensionMap::kMaxId; + +RtpHeaderExtensionMap::RtpHeaderExtensionMap() { + for (auto& type : types_) + type = kInvalidType; + for (auto& id : ids_) + id = kInvalidId; +} + +RtpHeaderExtensionMap::RtpHeaderExtensionMap( + rtc::ArrayView<const RtpExtension> extensions) + : RtpHeaderExtensionMap() { + for (const RtpExtension& extension : extensions) + RegisterByUri(extension.id, extension.uri); +} + +bool RtpHeaderExtensionMap::RegisterByType(int id, RTPExtensionType type) { + for (const ExtensionInfo& extension : kExtensions) + if (type == extension.type) + return Register(id, extension.type, extension.uri); + RTC_NOTREACHED(); + return false; +} + +bool RtpHeaderExtensionMap::RegisterByUri(int id, const std::string& uri) { + for (const ExtensionInfo& extension : kExtensions) + if (uri == extension.uri) + return Register(id, extension.type, extension.uri); + RTC_LOG(LS_WARNING) << "Unknown extension uri:'" << uri << "', id: " << id + << '.'; + return false; +} + +size_t RtpHeaderExtensionMap::GetTotalLengthInBytes( + rtc::ArrayView<const RtpExtensionSize> extensions) const { + // Header size of the extension block, see RFC3550 Section 5.3.1 + static constexpr size_t kRtpOneByteHeaderLength = 4; + // Header size of each individual extension, see RFC5285 Section 4.2 + static constexpr size_t kExtensionHeaderLength = 1; + size_t values_size = 0; + for (const RtpExtensionSize& extension : extensions) { + if (IsRegistered(extension.type)) + values_size += extension.value_size + kExtensionHeaderLength; + } + if (values_size == 0) + return 0; + size_t size = kRtpOneByteHeaderLength + values_size; + // Round up to the nearest size that is a multiple of 4. + // Which is same as round down (size + 3). + return size + 3 - (size + 3) % 4; +} + +int32_t RtpHeaderExtensionMap::Deregister(RTPExtensionType type) { + if (IsRegistered(type)) { + uint8_t id = GetId(type); + types_[id] = kInvalidType; + ids_[type] = kInvalidId; + } + return 0; +} + +bool RtpHeaderExtensionMap::Register(int id, + RTPExtensionType type, + const char* uri) { + RTC_DCHECK_GT(type, kRtpExtensionNone); + RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions); + + if (id < kMinId || id > kMaxId) { + RTC_LOG(LS_WARNING) << "Failed to register extension uri:'" << uri + << "' with invalid id:" << id << "."; + return false; + } + + if (GetType(id) == type) { // Same type/id pair already registered. + RTC_LOG(LS_VERBOSE) << "Reregistering extension uri:'" << uri + << "', id:" << id; + return true; + } + + if (GetType(id) != kInvalidType) { // |id| used by another extension type. + RTC_LOG(LS_WARNING) << "Failed to register extension uri:'" << uri + << "', id:" << id + << ". Id already in use by extension type " + << static_cast<int>(GetType(id)); + return false; + } + RTC_DCHECK(!IsRegistered(type)); + + types_[id] = type; + // There is a run-time check above id fits into uint8_t. + ids_[type] = static_cast<uint8_t>(id); + return true; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc new file mode 100644 index 0000000000..5eb8f1a62d --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc @@ -0,0 +1,114 @@ +/* + * 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 "modules/rtp_rtcp/include/rtp_header_extension_map.h" + +#include <vector> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "test/gtest.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +TEST(RtpHeaderExtensionTest, RegisterByType) { + RtpHeaderExtensionMap map; + EXPECT_FALSE(map.IsRegistered(TransmissionOffset::kId)); + + EXPECT_TRUE(map.RegisterByType(3, TransmissionOffset::kId)); + + EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId)); + EXPECT_EQ(3, map.GetId(TransmissionOffset::kId)); + EXPECT_EQ(TransmissionOffset::kId, map.GetType(3)); +} + +TEST(RtpHeaderExtensionTest, RegisterByUri) { + RtpHeaderExtensionMap map; + + EXPECT_TRUE(map.RegisterByUri(3, TransmissionOffset::kUri)); + + EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId)); + EXPECT_EQ(3, map.GetId(TransmissionOffset::kId)); + EXPECT_EQ(TransmissionOffset::kId, map.GetType(3)); +} + +TEST(RtpHeaderExtensionTest, RegisterWithTrait) { + RtpHeaderExtensionMap map; + + EXPECT_TRUE(map.Register<TransmissionOffset>(3)); + + EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId)); + EXPECT_EQ(3, map.GetId(TransmissionOffset::kId)); + EXPECT_EQ(TransmissionOffset::kId, map.GetType(3)); +} + +TEST(RtpHeaderExtensionTest, RegisterDuringContruction) { + const std::vector<RtpExtension> config = {{TransmissionOffset::kUri, 1}, + {AbsoluteSendTime::kUri, 3}}; + const RtpHeaderExtensionMap map(config); + + EXPECT_EQ(1, map.GetId(TransmissionOffset::kId)); + EXPECT_EQ(3, map.GetId(AbsoluteSendTime::kId)); +} + +TEST(RtpHeaderExtensionTest, RegisterIllegalArg) { + RtpHeaderExtensionMap map; + // Valid range for id: [1-14]. + EXPECT_FALSE(map.Register<TransmissionOffset>(0)); + EXPECT_FALSE(map.Register<TransmissionOffset>(15)); +} + +TEST(RtpHeaderExtensionTest, Idempotent) { + RtpHeaderExtensionMap map; + + EXPECT_TRUE(map.Register<TransmissionOffset>(3)); + EXPECT_TRUE(map.Register<TransmissionOffset>(3)); + + map.Deregister(TransmissionOffset::kId); + map.Deregister(TransmissionOffset::kId); +} + +TEST(RtpHeaderExtensionTest, NonUniqueId) { + RtpHeaderExtensionMap map; + EXPECT_TRUE(map.Register<TransmissionOffset>(3)); + + EXPECT_FALSE(map.Register<AudioLevel>(3)); + EXPECT_TRUE(map.Register<AudioLevel>(4)); +} + +TEST(RtpHeaderExtensionTest, GetTotalLength) { + RtpHeaderExtensionMap map; + constexpr RtpExtensionSize kExtensionSizes[] = { + {TransmissionOffset::kId, TransmissionOffset::kValueSizeBytes}}; + EXPECT_EQ(0u, map.GetTotalLengthInBytes(kExtensionSizes)); + EXPECT_TRUE(map.Register<TransmissionOffset>(3)); + static constexpr size_t kRtpOneByteHeaderLength = 4; + EXPECT_EQ(kRtpOneByteHeaderLength + (TransmissionOffset::kValueSizeBytes + 1), + map.GetTotalLengthInBytes(kExtensionSizes)); +} + +TEST(RtpHeaderExtensionTest, GetType) { + RtpHeaderExtensionMap map; + EXPECT_EQ(RtpHeaderExtensionMap::kInvalidType, map.GetType(3)); + EXPECT_TRUE(map.Register<TransmissionOffset>(3)); + + EXPECT_EQ(TransmissionOffset::kId, map.GetType(3)); +} + +TEST(RtpHeaderExtensionTest, GetId) { + RtpHeaderExtensionMap map; + EXPECT_EQ(RtpHeaderExtensionMap::kInvalidId, + map.GetId(TransmissionOffset::kId)); + EXPECT_TRUE(map.Register<TransmissionOffset>(3)); + + EXPECT_EQ(3, map.GetId(TransmissionOffset::kId)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc new file mode 100644 index 0000000000..a6ee24cf82 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtp_header_extensions.h" + +#include "modules/rtp_rtcp/include/rtp_cvo.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { +// Absolute send time in RTP streams. +// +// The absolute send time is signaled to the receiver in-band using the +// general mechanism for RTP header extensions [RFC5285]. The payload +// of this extension (the transmitted value) is a 24-bit unsigned integer +// containing the sender's current time in seconds as a fixed point number +// with 18 bits fractional part. +// +// The form of the absolute send time extension block: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=2 | absolute send time | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +constexpr RTPExtensionType AbsoluteSendTime::kId; +constexpr uint8_t AbsoluteSendTime::kValueSizeBytes; +constexpr const char AbsoluteSendTime::kUri[]; + +bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data, + uint32_t* time_24bits) { + if (data.size() != 3) + return false; + *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data()); + return true; +} + +bool AbsoluteSendTime::Write(uint8_t* data, uint32_t time_24bits) { + RTC_DCHECK_LE(time_24bits, 0x00FFFFFF); + ByteWriter<uint32_t, 3>::WriteBigEndian(data, time_24bits); + return true; +} + +// An RTP Header Extension for Client-to-Mixer Audio Level Indication +// +// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/ +// +// The form of the audio level extension block: +// +// 0 1 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=0 |V| level | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +constexpr RTPExtensionType AudioLevel::kId; +constexpr uint8_t AudioLevel::kValueSizeBytes; +constexpr const char AudioLevel::kUri[]; + +bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data, + bool* voice_activity, + uint8_t* audio_level) { + if (data.size() != 1) + return false; + *voice_activity = (data[0] & 0x80) != 0; + *audio_level = data[0] & 0x7F; + return true; +} + +bool AudioLevel::Write(uint8_t* data, + bool voice_activity, + uint8_t audio_level) { + RTC_CHECK_LE(audio_level, 0x7f); + data[0] = (voice_activity ? 0x80 : 0x00) | audio_level; + return true; +} + +// From RFC 5450: Transmission Time Offsets in RTP Streams. +// +// The transmission time is signaled to the receiver in-band using the +// general mechanism for RTP header extensions [RFC5285]. The payload +// of this extension (the transmitted value) is a 24-bit signed integer. +// When added to the RTP timestamp of the packet, it represents the +// "effective" RTP transmission time of the packet, on the RTP +// timescale. +// +// The form of the transmission offset extension block: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=2 | transmission offset | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +constexpr RTPExtensionType TransmissionOffset::kId; +constexpr uint8_t TransmissionOffset::kValueSizeBytes; +constexpr const char TransmissionOffset::kUri[]; + +bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data, + int32_t* rtp_time) { + if (data.size() != 3) + return false; + *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data()); + return true; +} + +bool TransmissionOffset::Write(uint8_t* data, int32_t rtp_time) { + RTC_DCHECK_LE(rtp_time, 0x00ffffff); + ByteWriter<int32_t, 3>::WriteBigEndian(data, rtp_time); + return true; +} + +// 0 1 2 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | L=1 |transport wide sequence number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +constexpr RTPExtensionType TransportSequenceNumber::kId; +constexpr uint8_t TransportSequenceNumber::kValueSizeBytes; +constexpr const char TransportSequenceNumber::kUri[]; + +bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data, + uint16_t* value) { + if (data.size() != 2) + return false; + *value = ByteReader<uint16_t>::ReadBigEndian(data.data()); + return true; +} + +bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) { + ByteWriter<uint16_t>::WriteBigEndian(data, value); + return true; +} + +// Coordination of Video Orientation in RTP streams. +// +// Coordination of Video Orientation consists in signaling of the current +// orientation of the image captured on the sender side to the receiver for +// appropriate rendering and displaying. +// +// 0 1 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=0 |0 0 0 0 C F R R| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +constexpr RTPExtensionType VideoOrientation::kId; +constexpr uint8_t VideoOrientation::kValueSizeBytes; +constexpr const char VideoOrientation::kUri[]; + +bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data, + VideoRotation* rotation) { + if (data.size() != 1) + return false; + *rotation = ConvertCVOByteToVideoRotation(data[0]); + return true; +} + +bool VideoOrientation::Write(uint8_t* data, VideoRotation rotation) { + data[0] = ConvertVideoRotationToCVOByte(rotation); + return true; +} + +bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data, + uint8_t* value) { + if (data.size() != 1) + return false; + *value = data[0]; + return true; +} + +bool VideoOrientation::Write(uint8_t* data, uint8_t value) { + data[0] = value; + return true; +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=2 | MIN delay | MAX delay | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +constexpr RTPExtensionType PlayoutDelayLimits::kId; +constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes; +constexpr const char PlayoutDelayLimits::kUri[]; + +bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data, + PlayoutDelay* playout_delay) { + RTC_DCHECK(playout_delay); + if (data.size() != 3) + return false; + uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data()); + uint16_t min_raw = (raw >> 12); + uint16_t max_raw = (raw & 0xfff); + if (min_raw > max_raw) + return false; + playout_delay->min_ms = min_raw * kGranularityMs; + playout_delay->max_ms = max_raw * kGranularityMs; + return true; +} + +bool PlayoutDelayLimits::Write(uint8_t* data, + const PlayoutDelay& playout_delay) { + RTC_DCHECK_LE(0, playout_delay.min_ms); + RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms); + RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs); + // Convert MS to value to be sent on extension header. + uint32_t min_delay = playout_delay.min_ms / kGranularityMs; + uint32_t max_delay = playout_delay.max_ms / kGranularityMs; + ByteWriter<uint32_t, 3>::WriteBigEndian(data, (min_delay << 12) | max_delay); + return true; +} + +// CSRCAudioLevel +// Sample Audio Level Encoding Using the One-Byte Header Format +// Note that the range of len is 1 to 15 which is encoded as 0 to 14 +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=2 |0| level 1 |0| level 2 |0| level 3 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +constexpr RTPExtensionType CsrcAudioLevel::kId; +constexpr const char* CsrcAudioLevel::kUri; + +bool CsrcAudioLevel::Parse(rtc::ArrayView<const uint8_t> data, + CsrcAudioLevelList* csrcAudioLevels) { + if (data.size() < 1 || data.size() > kRtpCsrcSize) + return false; + csrcAudioLevels->numAudioLevels = data.size(); + for(uint8_t i = 0; i < csrcAudioLevels->numAudioLevels; i++) { + // Ensure range is 0 to 127 inclusive + csrcAudioLevels->arrOfAudioLevels[i] = 0x7f & data[i]; + } + return true; +} + +size_t CsrcAudioLevel::ValueSize(const CsrcAudioLevelList& csrcAudioLevels) { + return csrcAudioLevels.numAudioLevels; +} + +bool CsrcAudioLevel::Write(uint8_t* data, + const CsrcAudioLevelList& csrcAudioLevels) { + RTC_DCHECK_GE(csrcAudioLevels.numAudioLevels, 0); + for(uint8_t i = 0; i < csrcAudioLevels.numAudioLevels; i++) { + data[i] = csrcAudioLevels.arrOfAudioLevels[i] & 0x7f; + } + // This extension if used must have at least one audio level + return csrcAudioLevels.numAudioLevels; +} + +// Video Content Type. +// +// E.g. default video or screenshare. +// +// 0 1 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=0 | Content type | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +constexpr RTPExtensionType VideoContentTypeExtension::kId; +constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes; +constexpr const char VideoContentTypeExtension::kUri[]; + +bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data, + VideoContentType* content_type) { + if (data.size() == 1 && + videocontenttypehelpers::IsValidContentType(data[0])) { + *content_type = static_cast<VideoContentType>(data[0]); + return true; + } + return false; +} + +bool VideoContentTypeExtension::Write(uint8_t* data, + VideoContentType content_type) { + data[0] = static_cast<uint8_t>(content_type); + return true; +} + +// Video Timing. +// 6 timestamps in milliseconds counted from capture time stored in rtp header: +// encode start/finish, packetization complete, pacer exit and reserved for +// modification by the network modification. |flags| is a bitmask and has the +// following allowed values: +// 0 = Valid data, but no flags available (backwards compatibility) +// 1 = Frame marked as timing frame due to cyclic timer. +// 2 = Frame marked as timing frame due to size being outside limit. +// 255 = Invalid. The whole timing frame extension should be ignored. +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=12| flags | encode start ms delta | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | encode finish ms delta | packetizer finish ms delta | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | pacer exit ms delta | network timestamp ms delta | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | network2 timestamp ms delta | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +constexpr RTPExtensionType VideoTimingExtension::kId; +constexpr uint8_t VideoTimingExtension::kValueSizeBytes; +constexpr const char VideoTimingExtension::kUri[]; + +bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data, + VideoSendTiming* timing) { + RTC_DCHECK(timing); + // TODO(sprang): Deprecate support for old wire format. + ptrdiff_t off = 0; + switch (data.size()) { + case kValueSizeBytes - 1: + timing->flags = 0; + off = 1; // Old wire format without the flags field. + break; + case kValueSizeBytes: + timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data()); + break; + default: + return false; + } + + timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian( + data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off); + timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian( + data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off); + timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian( + data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off); + timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian( + data.data() + VideoSendTiming::kPacerExitDeltaOffset - off); + timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian( + data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off); + timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian( + data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off); + return true; +} + +bool VideoTimingExtension::Write(uint8_t* data, const VideoSendTiming& timing) { + ByteWriter<uint8_t>::WriteBigEndian(data + VideoSendTiming::kFlagsOffset, + timing.flags); + ByteWriter<uint16_t>::WriteBigEndian( + data + VideoSendTiming::kEncodeStartDeltaOffset, + timing.encode_start_delta_ms); + ByteWriter<uint16_t>::WriteBigEndian( + data + VideoSendTiming::kEncodeFinishDeltaOffset, + timing.encode_finish_delta_ms); + ByteWriter<uint16_t>::WriteBigEndian( + data + VideoSendTiming::kPacketizationFinishDeltaOffset, + timing.packetization_finish_delta_ms); + ByteWriter<uint16_t>::WriteBigEndian( + data + VideoSendTiming::kPacerExitDeltaOffset, + timing.pacer_exit_delta_ms); + ByteWriter<uint16_t>::WriteBigEndian( + data + VideoSendTiming::kNetworkTimestampDeltaOffset, + timing.network_timestamp_delta_ms); + ByteWriter<uint16_t>::WriteBigEndian( + data + VideoSendTiming::kNetwork2TimestampDeltaOffset, + timing.network2_timestamp_delta_ms); + return true; +} + +bool VideoTimingExtension::Write(uint8_t* data, + uint16_t time_delta_ms, + uint8_t offset) { + RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t)); + ByteWriter<uint16_t>::WriteBigEndian(data + offset, time_delta_ms); + return true; +} + +bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data, + StringRtpHeaderExtension* str) { + if (data.empty() || data[0] == 0) // Valid string extension can't be empty. + return false; + str->Set(data); + RTC_DCHECK(!str->empty()); + return true; +} + +bool BaseRtpStringExtension::Write(uint8_t* data, + const StringRtpHeaderExtension& str) { + RTC_DCHECK_GE(str.size(), 1); + RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize); + memcpy(data, str.data(), str.size()); + return true; +} + +bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data, + std::string* str) { + if (data.empty() || data[0] == 0) // Valid string extension can't be empty. + return false; + const char* cstr = reinterpret_cast<const char*>(data.data()); + // If there is a \0 character in the middle of the |data|, treat it as end + // of the string. Well-formed string extensions shouldn't contain it. + str->assign(cstr, strnlen(cstr, data.size())); + RTC_DCHECK(!str->empty()); + return true; +} + +bool BaseRtpStringExtension::Write(uint8_t* data, const std::string& str) { + RTC_DCHECK_GE(str.size(), 1); + RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize); + memcpy(data, str.data(), str.size()); + return true; +} + +// Constant declarations for string RTP header extension types. + +constexpr RTPExtensionType RtpStreamId::kId; +constexpr const char RtpStreamId::kUri[]; + +constexpr RTPExtensionType RepairedRtpStreamId::kId; +constexpr const char RepairedRtpStreamId::kUri[]; + +constexpr RTPExtensionType RtpMid::kId; +constexpr const char RtpMid::kUri[]; + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h new file mode 100644 index 0000000000..c360ff53ec --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_ + +#include <stdint.h> +#include <string> + +#include "api/array_view.h" +#include "api/video/video_content_type.h" +#include "api/video/video_rotation.h" +#include "api/video/video_timing.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" + +namespace webrtc { + +class AbsoluteSendTime { + public: + static constexpr RTPExtensionType kId = kRtpExtensionAbsoluteSendTime; + static constexpr uint8_t kValueSizeBytes = 3; + static constexpr const char kUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; + + static bool Parse(rtc::ArrayView<const uint8_t> data, uint32_t* time_24bits); + static size_t ValueSize(uint32_t time_24bits) { return kValueSizeBytes; } + static bool Write(uint8_t* data, uint32_t time_24bits); + + static constexpr uint32_t MsTo24Bits(int64_t time_ms) { + return static_cast<uint32_t>(((time_ms << 18) + 500) / 1000) & 0x00FFFFFF; + } +}; + +class AudioLevel { + public: + static constexpr RTPExtensionType kId = kRtpExtensionAudioLevel; + static constexpr uint8_t kValueSizeBytes = 1; + static constexpr const char kUri[] = + "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; + + static bool Parse(rtc::ArrayView<const uint8_t> data, + bool* voice_activity, + uint8_t* audio_level); + static size_t ValueSize(bool voice_activity, uint8_t audio_level) { + return kValueSizeBytes; + } + static bool Write(uint8_t* data, bool voice_activity, uint8_t audio_level); +}; + +class TransmissionOffset { + public: + static constexpr RTPExtensionType kId = kRtpExtensionTransmissionTimeOffset; + static constexpr uint8_t kValueSizeBytes = 3; + static constexpr const char kUri[] = "urn:ietf:params:rtp-hdrext:toffset"; + + static bool Parse(rtc::ArrayView<const uint8_t> data, int32_t* rtp_time); + static size_t ValueSize(int32_t rtp_time) { return kValueSizeBytes; } + static bool Write(uint8_t* data, int32_t rtp_time); +}; + +class TransportSequenceNumber { + public: + static constexpr RTPExtensionType kId = kRtpExtensionTransportSequenceNumber; + static constexpr uint8_t kValueSizeBytes = 2; + static constexpr const char kUri[] = + "http://www.ietf.org/id/" + "draft-holmer-rmcat-transport-wide-cc-extensions-01"; + static bool Parse(rtc::ArrayView<const uint8_t> data, uint16_t* value); + static size_t ValueSize(uint16_t value) { return kValueSizeBytes; } + static bool Write(uint8_t* data, uint16_t value); +}; + +class VideoOrientation { + public: + static constexpr RTPExtensionType kId = kRtpExtensionVideoRotation; + static constexpr uint8_t kValueSizeBytes = 1; + static constexpr const char kUri[] = "urn:3gpp:video-orientation"; + + static bool Parse(rtc::ArrayView<const uint8_t> data, VideoRotation* value); + static size_t ValueSize(VideoRotation) { return kValueSizeBytes; } + static bool Write(uint8_t* data, VideoRotation value); + static bool Parse(rtc::ArrayView<const uint8_t> data, uint8_t* value); + static size_t ValueSize(uint8_t value) { return kValueSizeBytes; } + static bool Write(uint8_t* data, uint8_t value); +}; + +class PlayoutDelayLimits { + public: + static constexpr RTPExtensionType kId = kRtpExtensionPlayoutDelay; + static constexpr uint8_t kValueSizeBytes = 3; + static constexpr const char kUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"; + + // Playout delay in milliseconds. A playout delay limit (min or max) + // has 12 bits allocated. This allows a range of 0-4095 values which + // translates to a range of 0-40950 in milliseconds. + static constexpr int kGranularityMs = 10; + // Maximum playout delay value in milliseconds. + static constexpr int kMaxMs = 0xfff * kGranularityMs; // 40950. + + static bool Parse(rtc::ArrayView<const uint8_t> data, + PlayoutDelay* playout_delay); + static size_t ValueSize(const PlayoutDelay&) { + return kValueSizeBytes; + } + static bool Write(uint8_t* data, const PlayoutDelay& playout_delay); +}; + +class VideoContentTypeExtension { + public: + static constexpr RTPExtensionType kId = kRtpExtensionVideoContentType; + static constexpr uint8_t kValueSizeBytes = 1; + static constexpr const char kUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type"; + + static bool Parse(rtc::ArrayView<const uint8_t> data, + VideoContentType* content_type); + static size_t ValueSize(VideoContentType) { + return kValueSizeBytes; + } + static bool Write(uint8_t* data, VideoContentType content_type); +}; + +class VideoTimingExtension { + public: + static constexpr RTPExtensionType kId = kRtpExtensionVideoTiming; + static constexpr uint8_t kValueSizeBytes = 13; + static constexpr const char kUri[] = + "http://www.webrtc.org/experiments/rtp-hdrext/video-timing"; + + static bool Parse(rtc::ArrayView<const uint8_t> data, + VideoSendTiming* timing); + static size_t ValueSize(const VideoSendTiming&) { return kValueSizeBytes; } + static bool Write(uint8_t* data, const VideoSendTiming& timing); + + static size_t ValueSize(uint16_t time_delta_ms, uint8_t idx) { + return kValueSizeBytes; + } + // Writes only single time delta to position idx. + static bool Write(uint8_t* data, uint16_t time_delta_ms, uint8_t idx); +}; + +class CsrcAudioLevel { + public: + static constexpr RTPExtensionType kId = kRtpExtensionCsrcAudioLevel; + static constexpr const char* kUri = + "urn:ietf:params:rtp-hdrext:csrc-audio-level"; + + static bool Parse(rtc::ArrayView<const uint8_t> data, + CsrcAudioLevelList* csrcAudioLevels); + static size_t ValueSize(const CsrcAudioLevelList& csrcAudioLevels); + static bool Write(uint8_t* data, const CsrcAudioLevelList& csrcAudioLevels); +}; + +// Base extension class for RTP header extensions which are strings. +// Subclasses must defined kId and kUri static constexpr members. +class BaseRtpStringExtension { + public: + static bool Parse(rtc::ArrayView<const uint8_t> data, + StringRtpHeaderExtension* str); + static size_t ValueSize(const StringRtpHeaderExtension& str) { + return str.size(); + } + static bool Write(uint8_t* data, const StringRtpHeaderExtension& str); + + static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* str); + static size_t ValueSize(const std::string& str) { return str.size(); } + static bool Write(uint8_t* data, const std::string& str); +}; + +class RtpStreamId : public BaseRtpStringExtension { + public: + static constexpr RTPExtensionType kId = kRtpExtensionRtpStreamId; + static constexpr const char kUri[] = + "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id"; +}; + +class RepairedRtpStreamId : public BaseRtpStringExtension { + public: + static constexpr RTPExtensionType kId = kRtpExtensionRepairedRtpStreamId; + static constexpr const char kUri[] = + "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"; +}; + +class RtpMid : public BaseRtpStringExtension { + public: + static constexpr RTPExtensionType kId = kRtpExtensionMid; + static constexpr const char kUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid"; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_parser.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_parser.cc new file mode 100644 index 0000000000..5656a282fe --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_parser.cc @@ -0,0 +1,79 @@ +/* + * 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 "modules/rtp_rtcp/include/rtp_header_parser.h" + +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/criticalsection.h" + +namespace webrtc { + +class RtpHeaderParserImpl : public RtpHeaderParser { + public: + RtpHeaderParserImpl(); + virtual ~RtpHeaderParserImpl() {} + + bool Parse(const uint8_t* packet, + size_t length, + RTPHeader* header, + bool secured) const override; + + bool RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id) override; + + bool DeregisterRtpHeaderExtension(RTPExtensionType type) override; + + private: + rtc::CriticalSection critical_section_; + RtpHeaderExtensionMap rtp_header_extension_map_ + RTC_GUARDED_BY(critical_section_); +}; + +RtpHeaderParser* RtpHeaderParser::Create() { + return new RtpHeaderParserImpl; +} + +RtpHeaderParserImpl::RtpHeaderParserImpl() {} + +bool RtpHeaderParser::IsRtcp(const uint8_t* packet, size_t length) { + RtpUtility::RtpHeaderParser rtp_parser(packet, length); + return rtp_parser.RTCP(); +} + +bool RtpHeaderParserImpl::Parse(const uint8_t* packet, + size_t length, + RTPHeader* header, + bool secured) const { + RtpUtility::RtpHeaderParser rtp_parser(packet, length); + memset(header, 0, sizeof(*header)); + + RtpHeaderExtensionMap map; + { + rtc::CritScope cs(&critical_section_); + map = rtp_header_extension_map_; + } + + const bool valid_rtpheader = rtp_parser.Parse(header, &map, secured); + if (!valid_rtpheader) { + return false; + } + return true; +} + +bool RtpHeaderParserImpl::RegisterRtpHeaderExtension(RTPExtensionType type, + uint8_t id) { + rtc::CritScope cs(&critical_section_); + return rtp_header_extension_map_.RegisterByType(id, type); +} + +bool RtpHeaderParserImpl::DeregisterRtpHeaderExtension(RTPExtensionType type) { + rtc::CritScope cs(&critical_section_); + return rtp_header_extension_map_.Deregister(type) == 0; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.cc new file mode 100644 index 0000000000..f2a9709ca4 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.cc @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtp_packet.h" + +#include <cstring> +#include <utility> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/random.h" + +namespace webrtc { +namespace { +constexpr size_t kFixedHeaderSize = 12; +constexpr uint8_t kRtpVersion = 2; +constexpr uint16_t kOneByteExtensionId = 0xBEDE; +constexpr size_t kOneByteHeaderSize = 1; +constexpr size_t kDefaultPacketSize = 1500; +} // namespace + +constexpr int RtpPacket::kMaxExtensionHeaders; +constexpr int RtpPacket::kMinExtensionId; +constexpr int RtpPacket::kMaxExtensionId; + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P|X| CC |M| PT | sequence number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | synchronization source (SSRC) identifier | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | Contributing source (CSRC) identifiers | +// | .... | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// |One-byte eXtensions id = 0xbede| length in 32bits | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Extensions | +// | .... | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | Payload | +// | .... : padding... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | padding | Padding size | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +RtpPacket::RtpPacket() : RtpPacket(nullptr, kDefaultPacketSize) {} + +RtpPacket::RtpPacket(const ExtensionManager* extensions) + : RtpPacket(extensions, kDefaultPacketSize) {} + +RtpPacket::RtpPacket(const RtpPacket&) = default; + +RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity) + : buffer_(capacity) { + RTC_DCHECK_GE(capacity, kFixedHeaderSize); + Clear(); + if (extensions) { + IdentifyExtensions(*extensions); + } else { + for (size_t i = 0; i < kMaxExtensionHeaders; ++i) + extension_entries_[i].type = ExtensionManager::kInvalidType; + } +} + +RtpPacket::~RtpPacket() {} + +void RtpPacket::IdentifyExtensions(const ExtensionManager& extensions) { + for (int i = 0; i < kMaxExtensionHeaders; ++i) + extension_entries_[i].type = extensions.GetType(i + 1); +} + +bool RtpPacket::Parse(const uint8_t* buffer, size_t buffer_size) { + if (!ParseBuffer(buffer, buffer_size)) { + Clear(); + return false; + } + buffer_.SetData(buffer, buffer_size); + RTC_DCHECK_EQ(size(), buffer_size); + return true; +} + +bool RtpPacket::Parse(rtc::ArrayView<const uint8_t> packet) { + return Parse(packet.data(), packet.size()); +} + +bool RtpPacket::Parse(rtc::CopyOnWriteBuffer buffer) { + if (!ParseBuffer(buffer.cdata(), buffer.size())) { + Clear(); + return false; + } + size_t buffer_size = buffer.size(); + buffer_ = std::move(buffer); + RTC_DCHECK_EQ(size(), buffer_size); + return true; +} + +bool RtpPacket::Marker() const { + RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0); + return marker_; +} + +uint8_t RtpPacket::PayloadType() const { + RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f); + return payload_type_; +} + +uint16_t RtpPacket::SequenceNumber() const { + RTC_DCHECK_EQ(sequence_number_, + ByteReader<uint16_t>::ReadBigEndian(data() + 2)); + return sequence_number_; +} + +uint32_t RtpPacket::Timestamp() const { + RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4)); + return timestamp_; +} + +uint32_t RtpPacket::Ssrc() const { + RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8)); + return ssrc_; +} + +std::vector<uint32_t> RtpPacket::Csrcs() const { + size_t num_csrc = data()[0] & 0x0F; + RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4); + std::vector<uint32_t> csrcs(num_csrc); + for (size_t i = 0; i < num_csrc; ++i) { + csrcs[i] = + ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]); + } + return csrcs; +} + +size_t RtpPacket::headers_size() const { + return payload_offset_; +} + +size_t RtpPacket::payload_size() const { + return payload_size_; +} + +size_t RtpPacket::padding_size() const { + return padding_size_; +} + +rtc::ArrayView<const uint8_t> RtpPacket::payload() const { + return rtc::MakeArrayView(data() + payload_offset_, payload_size_); +} + +rtc::CopyOnWriteBuffer RtpPacket::Buffer() const { + return buffer_; +} + +size_t RtpPacket::capacity() const { + return buffer_.capacity(); +} + +size_t RtpPacket::size() const { + size_t ret = payload_offset_ + payload_size_ + padding_size_; + RTC_DCHECK_EQ(buffer_.size(), ret); + return ret; +} + +const uint8_t* RtpPacket::data() const { + return buffer_.cdata(); +} + +size_t RtpPacket::FreeCapacity() const { + return capacity() - size(); +} + +size_t RtpPacket::MaxPayloadSize() const { + return capacity() - payload_offset_; +} + +void RtpPacket::CopyHeaderFrom(const RtpPacket& packet) { + RTC_DCHECK_GE(capacity(), packet.headers_size()); + + marker_ = packet.marker_; + payload_type_ = packet.payload_type_; + sequence_number_ = packet.sequence_number_; + timestamp_ = packet.timestamp_; + ssrc_ = packet.ssrc_; + payload_offset_ = packet.payload_offset_; + for (size_t i = 0; i < kMaxExtensionHeaders; ++i) { + extension_entries_[i] = packet.extension_entries_[i]; + } + extensions_size_ = packet.extensions_size_; + buffer_.SetData(packet.data(), packet.headers_size()); + // Reset payload and padding. + payload_size_ = 0; + padding_size_ = 0; +} + +void RtpPacket::SetMarker(bool marker_bit) { + marker_ = marker_bit; + if (marker_) { + WriteAt(1, data()[1] | 0x80); + } else { + WriteAt(1, data()[1] & 0x7F); + } +} + +void RtpPacket::SetPayloadType(uint8_t payload_type) { + RTC_DCHECK_LE(payload_type, 0x7Fu); + payload_type_ = payload_type; + WriteAt(1, (data()[1] & 0x80) | payload_type); +} + +void RtpPacket::SetSequenceNumber(uint16_t seq_no) { + sequence_number_ = seq_no; + ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no); +} + +void RtpPacket::SetTimestamp(uint32_t timestamp) { + timestamp_ = timestamp; + ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp); +} + +void RtpPacket::SetSsrc(uint32_t ssrc) { + ssrc_ = ssrc; + ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc); +} + +void RtpPacket::SetCsrcs(const std::vector<uint32_t>& csrcs) { + RTC_DCHECK_EQ(extensions_size_, 0); + RTC_DCHECK_EQ(payload_size_, 0); + RTC_DCHECK_EQ(padding_size_, 0); + RTC_DCHECK_LE(csrcs.size(), 0x0fu); + RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity()); + payload_offset_ = kFixedHeaderSize + 4 * csrcs.size(); + WriteAt(0, (data()[0] & 0xF0) | rtc::dchecked_cast<uint8_t>(csrcs.size())); + size_t offset = kFixedHeaderSize; + for (uint32_t csrc : csrcs) { + ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc); + offset += 4; + } + buffer_.SetSize(payload_offset_); +} + +bool RtpPacket::HasRawExtension(int id) const { + if (id == ExtensionManager::kInvalidId) + return false; + RTC_DCHECK_GE(id, kMinExtensionId); + RTC_DCHECK_LE(id, kMaxExtensionId); + return extension_entries_[id - 1].offset != 0; +} + +rtc::ArrayView<const uint8_t> RtpPacket::GetRawExtension(int id) const { + if (id == ExtensionManager::kInvalidId) + return nullptr; + RTC_DCHECK_GE(id, kMinExtensionId); + RTC_DCHECK_LE(id, kMaxExtensionId); + const ExtensionInfo& extension = extension_entries_[id - 1]; + if (extension.offset == 0) + return nullptr; + return rtc::MakeArrayView(data() + extension.offset, extension.length); +} + +bool RtpPacket::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) { + auto buffer = AllocateRawExtension(id, data.size()); + if (buffer.empty()) + return false; + RTC_DCHECK_EQ(buffer.size(), data.size()); + memcpy(buffer.data(), data.data(), data.size()); + return true; +} + +rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) { + if (id == ExtensionManager::kInvalidId) + return nullptr; + RTC_DCHECK_GE(id, kMinExtensionId); + RTC_DCHECK_LE(id, kMaxExtensionId); + RTC_DCHECK_GE(length, 1); + RTC_DCHECK_LE(length, 16); + + ExtensionInfo* extension_entry = &extension_entries_[id - 1]; + if (extension_entry->offset != 0) { + // Extension already reserved. Check if same length is used. + if (extension_entry->length == length) + return rtc::MakeArrayView(WriteAt(extension_entry->offset), length); + + RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type " + << static_cast<int>(extension_entry->type) + << ": expected " + << static_cast<int>(extension_entry->length) + << ". received " << length; + return nullptr; + } + if (payload_size_ > 0) { + RTC_LOG(LS_ERROR) << "Can't add new extension id " << id + << " after payload was set."; + return nullptr; + } + if (padding_size_ > 0) { + RTC_LOG(LS_ERROR) << "Can't add new extension id " << id + << " after padding was set."; + return nullptr; + } + + size_t num_csrc = data()[0] & 0x0F; + size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4; + size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length; + if (extensions_offset + new_extensions_size > capacity()) { + RTC_LOG(LS_ERROR) + << "Extension cannot be registered: Not enough space left in buffer."; + return nullptr; + } + + // All checks passed, write down the extension headers. + if (extensions_size_ == 0) { + RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4)); + WriteAt(0, data()[0] | 0x10); // Set extension bit. + // Profile specific ID always set to OneByteExtensionHeader. + ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4), + kOneByteExtensionId); + } + + uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4; + one_byte_header |= rtc::dchecked_cast<uint8_t>(length - 1); + WriteAt(extensions_offset + extensions_size_, one_byte_header); + + extension_entry->offset = rtc::dchecked_cast<uint16_t>( + extensions_offset + extensions_size_ + kOneByteHeaderSize); + extension_entry->length = rtc::dchecked_cast<uint8_t>(length); + extensions_size_ = rtc::dchecked_cast<uint16_t>(new_extensions_size); + + // Update header length field. + uint16_t extensions_words = (extensions_size_ + 3) / 4; // Wrap up to 32bit. + ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2), + extensions_words); + // Fill extension padding place with zeroes. + size_t extension_padding_size = 4 * extensions_words - extensions_size_; + memset(WriteAt(extensions_offset + extensions_size_), 0, + extension_padding_size); + payload_offset_ = extensions_offset + 4 * extensions_words; + buffer_.SetSize(payload_offset_); + return rtc::MakeArrayView(WriteAt(extension_entry->offset), length); +} + +uint8_t* RtpPacket::AllocatePayload(size_t size_bytes) { + // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause + // reallocation and memcpy. Keeping just header reduces memcpy size. + SetPayloadSize(0); + return SetPayloadSize(size_bytes); +} + +uint8_t* RtpPacket::SetPayloadSize(size_t size_bytes) { + RTC_DCHECK_EQ(padding_size_, 0); + if (payload_offset_ + size_bytes > capacity()) { + RTC_LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer."; + return nullptr; + } + payload_size_ = size_bytes; + buffer_.SetSize(payload_offset_ + payload_size_); + return WriteAt(payload_offset_); +} + +bool RtpPacket::SetPadding(uint8_t size_bytes, Random* random) { + RTC_DCHECK(random); + if (payload_offset_ + payload_size_ + size_bytes > capacity()) { + RTC_LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only " + << (capacity() - payload_offset_ - payload_size_) + << " bytes left in buffer."; + return false; + } + padding_size_ = size_bytes; + buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_); + if (padding_size_ > 0) { + size_t padding_offset = payload_offset_ + payload_size_; + size_t padding_end = padding_offset + padding_size_; + for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) { + WriteAt(offset, random->Rand<uint8_t>()); + } + WriteAt(padding_end - 1, padding_size_); + WriteAt(0, data()[0] | 0x20); // Set padding bit. + } else { + WriteAt(0, data()[0] & ~0x20); // Clear padding bit. + } + return true; +} + +void RtpPacket::Clear() { + marker_ = false; + payload_type_ = 0; + sequence_number_ = 0; + timestamp_ = 0; + ssrc_ = 0; + payload_offset_ = kFixedHeaderSize; + payload_size_ = 0; + padding_size_ = 0; + extensions_size_ = 0; + for (ExtensionInfo& location : extension_entries_) { + location.offset = 0; + location.length = 0; + } + + memset(WriteAt(0), 0, kFixedHeaderSize); + buffer_.SetSize(kFixedHeaderSize); + WriteAt(0, kRtpVersion << 6); +} + +bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) { + if (size < kFixedHeaderSize) { + return false; + } + const uint8_t version = buffer[0] >> 6; + if (version != kRtpVersion) { + return false; + } + const bool has_padding = (buffer[0] & 0x20) != 0; + const bool has_extension = (buffer[0] & 0x10) != 0; + const uint8_t number_of_crcs = buffer[0] & 0x0f; + marker_ = (buffer[1] & 0x80) != 0; + payload_type_ = buffer[1] & 0x7f; + + sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]); + timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]); + ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]); + if (size < kFixedHeaderSize + number_of_crcs * 4) { + return false; + } + payload_offset_ = kFixedHeaderSize + number_of_crcs * 4; + + if (has_padding) { + padding_size_ = buffer[size - 1]; + if (padding_size_ == 0) { + RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero"; + return false; + } + } else { + padding_size_ = 0; + } + + extensions_size_ = 0; + for (ExtensionInfo& location : extension_entries_) { + location.offset = 0; + location.length = 0; + } + if (has_extension) { + /* RTP header extension, RFC 3550. + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | defined by profile | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | header extension | + | .... | + */ + size_t extension_offset = payload_offset_ + 4; + if (extension_offset > size) { + return false; + } + uint16_t profile = + ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]); + size_t extensions_capacity = + ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]); + extensions_capacity *= 4; + if (extension_offset + extensions_capacity > size) { + return false; + } + if (profile != kOneByteExtensionId) { + RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile; + } else { + constexpr uint8_t kPaddingId = 0; + constexpr uint8_t kReservedId = 15; + while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) { + int id = buffer[extension_offset + extensions_size_] >> 4; + if (id == kReservedId) { + break; + } else if (id == kPaddingId) { + extensions_size_++; + continue; + } + uint8_t length = + 1 + (buffer[extension_offset + extensions_size_] & 0xf); + if (extensions_size_ + kOneByteHeaderSize + length > + extensions_capacity) { + RTC_LOG(LS_WARNING) << "Oversized rtp header extension."; + break; + } + + size_t idx = id - 1; + if (extension_entries_[idx].length != 0) { + RTC_LOG(LS_VERBOSE) + << "Duplicate rtp header extension id " << id << ". Overwriting."; + } + + extensions_size_ += kOneByteHeaderSize; + extension_entries_[idx].offset = + rtc::dchecked_cast<uint16_t>(extension_offset + extensions_size_); + extension_entries_[idx].length = rtc::dchecked_cast<uint16_t>(length); + extensions_size_ += length; + } + } + payload_offset_ = extension_offset + extensions_capacity; + } + + if (payload_offset_ + padding_size_ > size) { + return false; + } + payload_size_ = size - payload_offset_ - padding_size_; + return true; +} + +rtc::ArrayView<const uint8_t> RtpPacket::FindExtension( + ExtensionType type) const { + for (const ExtensionInfo& extension : extension_entries_) { + if (extension.type == type) { + if (extension.length == 0) { + // Extension is registered but not set. + return nullptr; + } + return rtc::MakeArrayView(data() + extension.offset, extension.length); + } + } + return nullptr; +} + +rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type, + size_t length) { + for (int i = 0; i < kMaxExtensionHeaders; ++i) { + if (extension_entries_[i].type == type) { + int extension_id = i + 1; + return AllocateRawExtension(extension_id, length); + } + } + // Extension not registered. + return nullptr; +} + +uint8_t* RtpPacket::WriteAt(size_t offset) { + return buffer_.data() + offset; +} + +void RtpPacket::WriteAt(size_t offset, uint8_t byte) { + buffer_.data()[offset] = byte; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.h new file mode 100644 index 0000000000..6fe79550d3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTP_PACKET_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_ + +#include <vector> + +#include "api/array_view.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/copyonwritebuffer.h" + +namespace webrtc { +class RtpHeaderExtensionMap; +class Random; + +class RtpPacket { + public: + using ExtensionType = RTPExtensionType; + using ExtensionManager = RtpHeaderExtensionMap; + static constexpr int kMaxExtensionHeaders = 14; + static constexpr int kMinExtensionId = 1; + static constexpr int kMaxExtensionId = 14; + + // |extensions| required for SetExtension/ReserveExtension functions during + // packet creating and used if available in Parse function. + // Adding and getting extensions will fail until |extensions| is + // provided via constructor or IdentifyExtensions function. + RtpPacket(); + explicit RtpPacket(const ExtensionManager* extensions); + RtpPacket(const RtpPacket&); + RtpPacket(const ExtensionManager* extensions, size_t capacity); + ~RtpPacket(); + + RtpPacket& operator=(const RtpPacket&) = default; + + // Parse and copy given buffer into Packet. + bool Parse(const uint8_t* buffer, size_t size); + bool Parse(rtc::ArrayView<const uint8_t> packet); + + // Parse and move given buffer into Packet. + bool Parse(rtc::CopyOnWriteBuffer packet); + + // Maps extensions id to their types. + void IdentifyExtensions(const ExtensionManager& extensions); + + // Header. + bool Marker() const; + uint8_t PayloadType() const; + uint16_t SequenceNumber() const; + uint32_t Timestamp() const; + uint32_t Ssrc() const; + std::vector<uint32_t> Csrcs() const; + + size_t headers_size() const; + + // Payload. + size_t payload_size() const; + size_t padding_size() const; + rtc::ArrayView<const uint8_t> payload() const; + + // Buffer. + rtc::CopyOnWriteBuffer Buffer() const; + size_t capacity() const; + size_t size() const; + const uint8_t* data() const; + size_t FreeCapacity() const; + size_t MaxPayloadSize() const; + + // Reset fields and buffer. + void Clear(); + + // Header setters. + void CopyHeaderFrom(const RtpPacket& packet); + void SetMarker(bool marker_bit); + void SetPayloadType(uint8_t payload_type); + void SetSequenceNumber(uint16_t seq_no); + void SetTimestamp(uint32_t timestamp); + void SetSsrc(uint32_t ssrc); + + // Writes csrc list. Assumes: + // a) There is enough room left in buffer. + // b) Extension headers, payload or padding data has not already been added. + void SetCsrcs(const std::vector<uint32_t>& csrcs); + + // Header extensions. + template <typename Extension> + bool HasExtension() const; + + template <typename Extension, typename... Values> + bool GetExtension(Values...) const; + + template <typename Extension, typename... Values> + bool SetExtension(Values...); + + template <typename Extension> + bool ReserveExtension(); + + // Following 4 helpers identify rtp header extension by |id| negotiated with + // remote peer and written in an rtp packet. + bool HasRawExtension(int id) const; + + // Returns place where extension with |id| is stored. + // Returns empty arrayview if extension is not present. + rtc::ArrayView<const uint8_t> GetRawExtension(int id) const; + + // Allocates and store header extension. Returns true on success. + bool SetRawExtension(int id, rtc::ArrayView<const uint8_t> data); + + // Allocates and returns place to store rtp header extension. + // Returns empty arrayview on failure. + rtc::ArrayView<uint8_t> AllocateRawExtension(int id, size_t length); + + // Find an extension |type|. + // Returns view of the raw extension or empty view on failure. + rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) const; + + // Find or allocate an extension |type|. Returns view of size |length| + // to write raw extension to or an empty view on failure. + rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length); + + // Reserve size_bytes for payload. Returns nullptr on failure. + uint8_t* SetPayloadSize(size_t size_bytes); + // Same as SetPayloadSize but doesn't guarantee to keep current payload. + uint8_t* AllocatePayload(size_t size_bytes); + bool SetPadding(uint8_t size_bytes, Random* random); + + private: + struct ExtensionInfo { + ExtensionType type; + uint16_t offset; + uint8_t length; + }; + + // Helper function for Parse. Fill header fields using data in given buffer, + // but does not touch packet own buffer, leaving packet in invalid state. + bool ParseBuffer(const uint8_t* buffer, size_t size); + + uint8_t* WriteAt(size_t offset); + void WriteAt(size_t offset, uint8_t byte); + + // Header. + bool marker_; + uint8_t payload_type_; + uint8_t padding_size_; + uint16_t sequence_number_; + uint32_t timestamp_; + uint32_t ssrc_; + size_t payload_offset_; // Match header size with csrcs and extensions. + size_t payload_size_; + + ExtensionInfo extension_entries_[kMaxExtensionHeaders]; + uint16_t extensions_size_ = 0; // Unaligned. + rtc::CopyOnWriteBuffer buffer_; +}; + +template <typename Extension> +bool RtpPacket::HasExtension() const { + return !FindExtension(Extension::kId).empty(); +} + +template <typename Extension, typename... Values> +bool RtpPacket::GetExtension(Values... values) const { + auto raw = FindExtension(Extension::kId); + if (raw.empty()) + return false; + return Extension::Parse(raw, values...); +} + +template <typename Extension, typename... Values> +bool RtpPacket::SetExtension(Values... values) { + const size_t value_size = Extension::ValueSize(values...); + if (value_size == 0 || value_size > 16) + return false; + auto buffer = AllocateExtension(Extension::kId, value_size); + if (buffer.empty()) + return false; + return Extension::Write(buffer.data(), values...); +} + +template <typename Extension> +bool RtpPacket::ReserveExtension() { + auto buffer = AllocateExtension(Extension::kId, Extension::kValueSizeBytes); + if (buffer.empty()) + return false; + memset(buffer.data(), 0, Extension::kValueSizeBytes); + return true; +} + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc new file mode 100644 index 0000000000..0272bd23ef --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc @@ -0,0 +1,223 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_packet_history.h" + +#include <algorithm> +#include <limits> +#include <utility> + +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { +namespace { +constexpr size_t kMinPacketRequestBytes = 50; +} // namespace +constexpr size_t RtpPacketHistory::kMaxCapacity; + +RtpPacketHistory::RtpPacketHistory(Clock* clock) + : clock_(clock), store_(false), prev_index_(0) {} + +RtpPacketHistory::~RtpPacketHistory() {} + +void RtpPacketHistory::SetStorePacketsStatus(bool enable, + uint16_t number_to_store) { + rtc::CritScope cs(&critsect_); + if (enable) { + if (store_) { + RTC_LOG(LS_WARNING) + << "Purging packet history in order to re-set status."; + Free(); + } + RTC_DCHECK(!store_); + Allocate(number_to_store); + } else { + Free(); + } +} + +void RtpPacketHistory::Allocate(size_t number_to_store) { + RTC_DCHECK_GT(number_to_store, 0); + RTC_DCHECK_LE(number_to_store, kMaxCapacity); + store_ = true; + stored_packets_.resize(number_to_store); +} + +void RtpPacketHistory::Free() { + if (!store_) { + return; + } + + stored_packets_.clear(); + + store_ = false; + prev_index_ = 0; +} + +bool RtpPacketHistory::StorePackets() const { + rtc::CritScope cs(&critsect_); + return store_; +} + +void RtpPacketHistory::PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet, + StorageType type, + bool sent) { + RTC_DCHECK(packet); + rtc::CritScope cs(&critsect_); + if (!store_) { + return; + } + + // If index we're about to overwrite contains a packet that has not + // yet been sent (probably pending in paced sender), we need to expand + // the buffer. + if (stored_packets_[prev_index_].packet && + stored_packets_[prev_index_].send_time == 0) { + size_t current_size = static_cast<uint16_t>(stored_packets_.size()); + if (current_size < kMaxCapacity) { + size_t expanded_size = std::max(current_size * 3 / 2, current_size + 1); + expanded_size = std::min(expanded_size, kMaxCapacity); + Allocate(expanded_size); + // Causes discontinuity, but that's OK-ish. FindSeqNum() will still work, + // but may be slower - at least until buffer has wrapped around once. + prev_index_ = current_size; + } + } + + // Store packet. + if (packet->capture_time_ms() <= 0) + packet->set_capture_time_ms(clock_->TimeInMilliseconds()); + stored_packets_[prev_index_].sequence_number = packet->SequenceNumber(); + stored_packets_[prev_index_].send_time = + (sent ? clock_->TimeInMilliseconds() : 0); + stored_packets_[prev_index_].storage_type = type; + stored_packets_[prev_index_].has_been_retransmitted = false; + stored_packets_[prev_index_].packet = std::move(packet); + + ++prev_index_; + if (prev_index_ >= stored_packets_.size()) { + prev_index_ = 0; + } +} + +bool RtpPacketHistory::HasRtpPacket(uint16_t sequence_number) const { + rtc::CritScope cs(&critsect_); + if (!store_) { + return false; + } + + int unused_index = 0; + return FindSeqNum(sequence_number, &unused_index); +} + +std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndSetSendTime( + uint16_t sequence_number, + int64_t min_elapsed_time_ms, + bool retransmit) { + rtc::CritScope cs(&critsect_); + if (!store_) { + return nullptr; + } + + int index = 0; + if (!FindSeqNum(sequence_number, &index)) { + RTC_LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number; + return nullptr; + } + RTC_DCHECK_EQ(sequence_number, + stored_packets_[index].packet->SequenceNumber()); + + // Verify elapsed time since last retrieve, but only for retransmissions and + // always send packet upon first retransmission request. + int64_t now = clock_->TimeInMilliseconds(); + if (min_elapsed_time_ms > 0 && retransmit && + stored_packets_[index].has_been_retransmitted && + ((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) { + return nullptr; + } + + if (retransmit) { + if (stored_packets_[index].storage_type == kDontRetransmit) { + // No bytes copied since this packet shouldn't be retransmitted. + return nullptr; + } + stored_packets_[index].has_been_retransmitted = true; + } + stored_packets_[index].send_time = clock_->TimeInMilliseconds(); + return GetPacket(index); +} + +std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacket(int index) const { + const RtpPacketToSend& stored = *stored_packets_[index].packet; + return std::unique_ptr<RtpPacketToSend>(new RtpPacketToSend(stored)); +} + +std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetBestFittingPacket( + size_t packet_length) const { + rtc::CritScope cs(&critsect_); + if (!store_) + return nullptr; + int index = FindBestFittingPacket(packet_length); + if (index < 0) + return nullptr; + return GetPacket(index); +} + +bool RtpPacketHistory::FindSeqNum(uint16_t sequence_number, int* index) const { + if (prev_index_ > 0) { + *index = prev_index_ - 1; + } else { + *index = stored_packets_.size() - 1; // Wrap. + } + uint16_t temp_sequence_number = stored_packets_[*index].sequence_number; + + int idx = *index - (temp_sequence_number - sequence_number); + if (idx >= 0 && idx < static_cast<int>(stored_packets_.size())) { + *index = idx; + temp_sequence_number = stored_packets_[*index].sequence_number; + } + + if (temp_sequence_number != sequence_number) { + // We did not found a match, search all. + for (uint16_t m = 0; m < stored_packets_.size(); m++) { + if (stored_packets_[m].sequence_number == sequence_number) { + *index = m; + temp_sequence_number = stored_packets_[*index].sequence_number; + break; + } + } + } + return temp_sequence_number == sequence_number && + stored_packets_[*index].packet; +} + +int RtpPacketHistory::FindBestFittingPacket(size_t size) const { + if (size < kMinPacketRequestBytes || stored_packets_.empty()) + return -1; + size_t min_diff = std::numeric_limits<size_t>::max(); + int best_index = -1; // Returned unchanged if we don't find anything. + for (size_t i = 0; i < stored_packets_.size(); ++i) { + if (!stored_packets_[i].packet) + continue; + size_t stored_size = stored_packets_[i].packet->size(); + size_t diff = + (stored_size > size) ? (stored_size - size) : (size - stored_size); + if (diff < min_diff) { + min_diff = diff; + best_index = static_cast<int>(i); + } + } + return best_index; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h new file mode 100644 index 0000000000..9f2e00c53a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h @@ -0,0 +1,85 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_ + +#include <memory> +#include <vector> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/thread_annotations.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class Clock; +class RtpPacketToSend; + +class RtpPacketHistory { + public: + static constexpr size_t kMaxCapacity = 9600; + explicit RtpPacketHistory(Clock* clock); + ~RtpPacketHistory(); + + void SetStorePacketsStatus(bool enable, uint16_t number_to_store); + bool StorePackets() const; + + void PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet, + StorageType type, + bool sent); + + // Gets stored RTP packet corresponding to the input |sequence number|. + // Returns nullptr if packet is not found. + // |min_elapsed_time_ms| is the minimum time that must have elapsed since + // the last time the packet was resent (parameter is ignored if set to zero). + // If the packet is found but the minimum time has not elapsed, returns + // nullptr. + std::unique_ptr<RtpPacketToSend> GetPacketAndSetSendTime( + uint16_t sequence_number, + int64_t min_elapsed_time_ms, + bool retransmit); + + std::unique_ptr<RtpPacketToSend> GetBestFittingPacket( + size_t packet_size) const; + + bool HasRtpPacket(uint16_t sequence_number) const; + + private: + struct StoredPacket { + uint16_t sequence_number = 0; + int64_t send_time = 0; + StorageType storage_type = kDontRetransmit; + bool has_been_retransmitted = false; + + std::unique_ptr<RtpPacketToSend> packet; + }; + + std::unique_ptr<RtpPacketToSend> GetPacket(int index) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + void Allocate(size_t number_to_store) RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + void Free() RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + bool FindSeqNum(uint16_t sequence_number, int* index) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + int FindBestFittingPacket(size_t size) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); + + Clock* clock_; + rtc::CriticalSection critsect_; + bool store_ RTC_GUARDED_BY(critsect_); + uint32_t prev_index_ RTC_GUARDED_BY(critsect_); + std::vector<StoredPacket> stored_packets_ RTC_GUARDED_BY(critsect_); + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpPacketHistory); +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc new file mode 100644 index 0000000000..fd3521ad5b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc @@ -0,0 +1,223 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_packet_history.h" + +#include <memory> +#include <utility> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "system_wrappers/include/clock.h" +#include "test/gtest.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class RtpPacketHistoryTest : public ::testing::Test { + protected: + static constexpr uint16_t kSeqNum = 88; + + RtpPacketHistoryTest() : fake_clock_(123456), hist_(&fake_clock_) {} + + SimulatedClock fake_clock_; + RtpPacketHistory hist_; + + std::unique_ptr<RtpPacketToSend> CreateRtpPacket(uint16_t seq_num) { + // Payload, ssrc, timestamp and extensions are irrelevant for this tests. + std::unique_ptr<RtpPacketToSend> packet(new RtpPacketToSend(nullptr)); + packet->SetSequenceNumber(seq_num); + packet->set_capture_time_ms(fake_clock_.TimeInMilliseconds()); + return packet; + } +}; + +TEST_F(RtpPacketHistoryTest, SetStoreStatus) { + EXPECT_FALSE(hist_.StorePackets()); + hist_.SetStorePacketsStatus(true, 10); + EXPECT_TRUE(hist_.StorePackets()); + hist_.SetStorePacketsStatus(false, 0); + EXPECT_FALSE(hist_.StorePackets()); +} + +TEST_F(RtpPacketHistoryTest, NoStoreStatus) { + EXPECT_FALSE(hist_.StorePackets()); + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + // Packet should not be stored. + EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false)); +} + +TEST_F(RtpPacketHistoryTest, GetRtpPacket_NotStored) { + hist_.SetStorePacketsStatus(true, 10); + EXPECT_FALSE(hist_.GetPacketAndSetSendTime(0, 0, false)); +} + +TEST_F(RtpPacketHistoryTest, PutRtpPacket) { + hist_.SetStorePacketsStatus(true, 10); + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum); + + EXPECT_FALSE(hist_.HasRtpPacket(kSeqNum)); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); +} + +TEST_F(RtpPacketHistoryTest, GetRtpPacket) { + hist_.SetStorePacketsStatus(true, 10); + int64_t capture_time_ms = 1; + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum); + packet->set_capture_time_ms(capture_time_ms); + rtc::CopyOnWriteBuffer buffer = packet->Buffer(); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + + std::unique_ptr<RtpPacketToSend> packet_out = + hist_.GetPacketAndSetSendTime(kSeqNum, 0, false); + EXPECT_TRUE(packet_out); + EXPECT_EQ(buffer, packet_out->Buffer()); + EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); +} + +TEST_F(RtpPacketHistoryTest, NoCaptureTime) { + hist_.SetStorePacketsStatus(true, 10); + fake_clock_.AdvanceTimeMilliseconds(1); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum); + packet->set_capture_time_ms(-1); + rtc::CopyOnWriteBuffer buffer = packet->Buffer(); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + + std::unique_ptr<RtpPacketToSend> packet_out = + hist_.GetPacketAndSetSendTime(kSeqNum, 0, false); + EXPECT_TRUE(packet_out); + EXPECT_EQ(buffer, packet_out->Buffer()); + EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); +} + +TEST_F(RtpPacketHistoryTest, DontRetransmit) { + hist_.SetStorePacketsStatus(true, 10); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum); + rtc::CopyOnWriteBuffer buffer = packet->Buffer(); + hist_.PutRtpPacket(std::move(packet), kDontRetransmit, false); + + std::unique_ptr<RtpPacketToSend> packet_out; + packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, true); + EXPECT_FALSE(packet_out); + + packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, false); + EXPECT_TRUE(packet_out); + + EXPECT_EQ(buffer.size(), packet_out->size()); + EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); +} + +TEST_F(RtpPacketHistoryTest, MinResendTime) { + static const int64_t kMinRetransmitIntervalMs = 100; + + hist_.SetStorePacketsStatus(true, 10); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum); + size_t len = packet->size(); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + + // First transmission: TimeToSendPacket() call from pacer. + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false)); + + fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs); + // Time has elapsed. + std::unique_ptr<RtpPacketToSend> packet_out = + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true); + EXPECT_TRUE(packet_out); + EXPECT_EQ(len, packet_out->size()); + EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); + + fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1); + // Time has not elapsed. Packet should be found, but no bytes copied. + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); + EXPECT_FALSE( + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true)); +} + +TEST_F(RtpPacketHistoryTest, EarlyFirstResend) { + static const int64_t kMinRetransmitIntervalMs = 100; + + hist_.SetStorePacketsStatus(true, 10); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum); + rtc::CopyOnWriteBuffer buffer = packet->Buffer(); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + + // First transmission: TimeToSendPacket() call from pacer. + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false)); + + fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1); + // Time has not elapsed, but this is the first retransmission request so + // allow anyway. + std::unique_ptr<RtpPacketToSend> packet_out = + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true); + EXPECT_TRUE(packet_out); + EXPECT_EQ(buffer, packet_out->Buffer()); + EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms()); + + fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1); + // Time has not elapsed. Packet should be found, but no bytes copied. + EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum)); + EXPECT_FALSE( + hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true)); +} + +TEST_F(RtpPacketHistoryTest, DynamicExpansion) { + hist_.SetStorePacketsStatus(true, 10); + + // Add 4 packets, and then send them. + for (int i = 0; i < 4; ++i) { + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + } + for (int i = 0; i < 4; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); + } + fake_clock_.AdvanceTimeMilliseconds(33); + + // Add 16 packets, and then send them. History should expand to make this + // work. + for (int i = 4; i < 20; ++i) { + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + } + for (int i = 4; i < 20; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); + } + + fake_clock_.AdvanceTimeMilliseconds(100); + + // Retransmit last 16 packets. + for (int i = 4; i < 20; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); + } +} + +TEST_F(RtpPacketHistoryTest, FullExpansion) { + static const int kSendSidePacketHistorySize = 600; + hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize); + for (size_t i = 0; i < RtpPacketHistory::kMaxCapacity + 1; ++i) { + std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i); + hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false); + } + + fake_clock_.AdvanceTimeMilliseconds(100); + + // Retransmit all packets currently in buffer. + for (size_t i = 1; i < RtpPacketHistory::kMaxCapacity + 1; ++i) { + EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false)); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.cc new file mode 100644 index 0000000000..1106e22a24 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.cc @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017 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/rtp_rtcp/source/rtp_packet_received.h" + +#include <vector> + +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +RtpPacketReceived::RtpPacketReceived() = default; +RtpPacketReceived::RtpPacketReceived(const ExtensionManager* extensions) + : RtpPacket(extensions) {} + +RtpPacketReceived::~RtpPacketReceived() {} + +void RtpPacketReceived::GetHeader(RTPHeader* header) const { + header->markerBit = Marker(); + header->payloadType = PayloadType(); + header->sequenceNumber = SequenceNumber(); + header->timestamp = Timestamp(); + header->ssrc = Ssrc(); + std::vector<uint32_t> csrcs = Csrcs(); + header->numCSRCs = rtc::dchecked_cast<uint8_t>(csrcs.size()); + for (size_t i = 0; i < csrcs.size(); ++i) { + header->arrOfCSRCs[i] = csrcs[i]; + } + header->paddingLength = padding_size(); + header->headerLength = headers_size(); + header->payload_type_frequency = payload_type_frequency(); + header->extension.hasTransmissionTimeOffset = + GetExtension<TransmissionOffset>( + &header->extension.transmissionTimeOffset); + header->extension.hasAbsoluteSendTime = + GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime); + header->extension.hasTransportSequenceNumber = + GetExtension<TransportSequenceNumber>( + &header->extension.transportSequenceNumber); + header->extension.hasAudioLevel = GetExtension<AudioLevel>( + &header->extension.voiceActivity, &header->extension.audioLevel); + header->extension.hasVideoRotation = + GetExtension<VideoOrientation>(&header->extension.videoRotation); + header->extension.hasVideoContentType = + GetExtension<VideoContentTypeExtension>( + &header->extension.videoContentType); + header->extension.has_video_timing = + GetExtension<VideoTimingExtension>(&header->extension.video_timing); + GetExtension<RtpStreamId>(&header->extension.stream_id); + GetExtension<RepairedRtpStreamId>(&header->extension.repaired_stream_id); + GetExtension<RtpMid>(&header->extension.mid); + GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h new file mode 100644 index 0000000000..4cf6b23bd7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_ + +#include <vector> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/source/rtp_packet.h" +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { +// Class to hold rtp packet with metadata for receiver side. +class RtpPacketReceived : public RtpPacket { + public: + RtpPacketReceived(); + explicit RtpPacketReceived(const ExtensionManager* extensions); + + ~RtpPacketReceived(); + + // TODO(danilchap): Remove this function when all code update to use RtpPacket + // directly. Function is there just for easier backward compatibilty. + void GetHeader(RTPHeader* header) const; + + // Time in local time base as close as it can to packet arrived on the + // network. + int64_t arrival_time_ms() const { return arrival_time_ms_; } + void set_arrival_time_ms(int64_t time) { arrival_time_ms_ = time; } + + // Estimated from Timestamp() using rtcp Sender Reports. + NtpTime capture_ntp_time() const { return capture_time_; } + void set_capture_ntp_time(NtpTime time) { capture_time_ = time; } + + // Flag if packet was recovered via RTX or FEC. + bool recovered() const { return recovered_; } + void set_recovered(bool value) { recovered_ = value; } + + int payload_type_frequency() const { return payload_type_frequency_; } + void set_payload_type_frequency(int value) { + payload_type_frequency_ = value; + } + + // Additional data bound to the RTP packet for use in application code, + // outside of WebRTC. + rtc::ArrayView<const uint8_t> application_data() const { + return application_data_; + } + void set_application_data(rtc::ArrayView<const uint8_t> data) { + application_data_.assign(data.begin(), data.end()); + } + + private: + NtpTime capture_time_; + int64_t arrival_time_ms_ = 0; + int payload_type_frequency_ = 0; + bool recovered_ = false; + std::vector<uint8_t> application_data_; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h new file mode 100644 index 0000000000..c287f0ca29 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_ + +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet.h" + +namespace webrtc { +// Class to hold rtp packet with metadata for sender side. +class RtpPacketToSend : public RtpPacket { + public: + explicit RtpPacketToSend(const ExtensionManager* extensions) + : RtpPacket(extensions) {} + RtpPacketToSend(const RtpPacketToSend& packet) = default; + RtpPacketToSend(const ExtensionManager* extensions, size_t capacity) + : RtpPacket(extensions, capacity) {} + + RtpPacketToSend& operator=(const RtpPacketToSend& packet) = default; + + // Time in local time base as close as it can to frame capture time. + int64_t capture_time_ms() const { return capture_time_ms_; } + + void set_capture_time_ms(int64_t time) { capture_time_ms_ = time; } + + void set_packetization_finish_time_ms(int64_t time) { + SetExtension<VideoTimingExtension>( + VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time), + VideoSendTiming::kPacketizationFinishDeltaOffset); + } + + void set_pacer_exit_time_ms(int64_t time) { + SetExtension<VideoTimingExtension>( + VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time), + VideoSendTiming::kPacerExitDeltaOffset); + } + + void set_network_time_ms(int64_t time) { + SetExtension<VideoTimingExtension>( + VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time), + VideoSendTiming::kNetworkTimestampDeltaOffset); + } + + void set_network2_time_ms(int64_t time) { + SetExtension<VideoTimingExtension>( + VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time), + VideoSendTiming::kNetwork2TimestampDeltaOffset); + } + + private: + int64_t capture_time_ms_ = 0; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc new file mode 100644 index 0000000000..f52b729cf1 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtp_packet_received.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" + +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "rtc_base/random.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { +using ::testing::ElementsAreArray; +using ::testing::IsEmpty; +using ::testing::make_tuple; + +constexpr int8_t kPayloadType = 100; +constexpr uint32_t kSsrc = 0x12345678; +constexpr uint16_t kSeqNum = 0x1234; +constexpr uint8_t kSeqNumFirstByte = kSeqNum >> 8; +constexpr uint8_t kSeqNumSecondByte = kSeqNum & 0xff; +constexpr uint32_t kTimestamp = 0x65431278; +constexpr uint8_t kTransmissionOffsetExtensionId = 1; +constexpr uint8_t kAudioLevelExtensionId = 9; +constexpr uint8_t kRtpStreamIdExtensionId = 0xa; +constexpr uint8_t kRtpMidExtensionId = 0xb; +constexpr uint8_t kVideoTimingExtensionId = 0xc; +constexpr int32_t kTimeOffset = 0x56ce; +constexpr bool kVoiceActive = true; +constexpr uint8_t kAudioLevel = 0x5a; +constexpr char kStreamId[] = "streamid"; +constexpr char kMid[] = "mid"; +constexpr size_t kMaxPaddingSize = 224u; +// clang-format off +constexpr uint8_t kMinimumPacket[] = { + 0x80, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78}; + +constexpr uint8_t kPacketWithTO[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78, + 0xbe, 0xde, 0x00, 0x01, + 0x12, 0x00, 0x56, 0xce}; + +constexpr uint8_t kPacketWithTOAndAL[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78, + 0xbe, 0xde, 0x00, 0x02, + 0x12, 0x00, 0x56, 0xce, + 0x90, 0x80|kAudioLevel, 0x00, 0x00}; + +constexpr uint8_t kPacketWithRsid[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78, + 0xbe, 0xde, 0x00, 0x03, + 0xa7, 's', 't', 'r', + 'e', 'a', 'm', 'i', + 'd' , 0x00, 0x00, 0x00}; + +constexpr uint8_t kPacketWithMid[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78, + 0xbe, 0xde, 0x00, 0x01, + 0xb2, 'm', 'i', 'd'}; + +constexpr uint8_t kCsrcAudioLevelExtensionId = 0xc; +constexpr uint8_t kCsrcAudioLevelsSize = 4; +constexpr uint8_t kCsrcAudioLevels[] = {0x7f, 0x00, 0x10, 0x08}; +constexpr uint8_t kPacketWithCsrcAudioLevels[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78, + 0xbe, 0xde, 0x00, 0x02, + (kCsrcAudioLevelExtensionId << 4) | (kCsrcAudioLevelsSize - 1), + 0x7f, 0x00, 0x10, + 0x08, 0x00, 0x00, 0x00}; + +constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465}; +constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'}; +constexpr uint8_t kPacketPaddingSize = 8; +constexpr uint8_t kPacket[] = { + 0xb2, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78, + 0x34, 0x56, 0x78, 0x90, + 0x32, 0x43, 0x54, 0x65, + 0xbe, 0xde, 0x00, 0x01, + 0x12, 0x00, 0x56, 0xce, + 'p', 'a', 'y', 'l', 'o', 'a', 'd', + 'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize}; + +constexpr uint8_t kPacketWithInvalidExtension[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSSrc. + 0xbe, 0xde, 0x00, 0x02, // Extension block of size 2 x 32bit words. + (kTransmissionOffsetExtensionId << 4) | 6, // (6+1)-byte extension, but + 'e', 'x', 't', // Transmission Offset + 'd', 'a', 't', 'a', // expected to be 3-bytes. + 'p', 'a', 'y', 'l', 'o', 'a', 'd'}; + +constexpr uint8_t kPacketWithLegacyTimingExtension[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSSrc. + 0xbe, 0xde, 0x00, 0x04, // Extension block of size 4 x 32bit words. + (kVideoTimingExtensionId << 4) + | VideoTimingExtension::kValueSizeBytes - 2, // Old format without flags. + 0x00, 0x01, 0x00, + 0x02, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +// clang-format on +} // namespace + +TEST(RtpPacketTest, CreateMinimum) { + RtpPacketToSend packet(nullptr); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + EXPECT_THAT(kMinimumPacket, ElementsAreArray(packet.data(), packet.size())); +} + +TEST(RtpPacketTest, CreateWithExtension) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + RtpPacketToSend packet(&extensions); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + packet.SetExtension<TransmissionOffset>(kTimeOffset); + EXPECT_THAT(kPacketWithTO, ElementsAreArray(packet.data(), packet.size())); +} + +TEST(RtpPacketTest, CreateWith2Extensions) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId); + RtpPacketToSend packet(&extensions); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + packet.SetExtension<TransmissionOffset>(kTimeOffset); + packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel); + EXPECT_THAT(kPacketWithTOAndAL, + ElementsAreArray(packet.data(), packet.size())); +} + +TEST(RtpPacketTest, CreateWithDynamicSizedExtensions) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId); + RtpPacketToSend packet(&extensions); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + packet.SetExtension<RtpStreamId>(kStreamId); + EXPECT_THAT(kPacketWithRsid, ElementsAreArray(packet.data(), packet.size())); +} + +TEST(RtpPacketTest, TryToCreateWithEmptyRsid) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId); + RtpPacketToSend packet(&extensions); + EXPECT_FALSE(packet.SetExtension<RtpStreamId>("")); +} + +TEST(RtpPacketTest, TryToCreateWithLongRsid) { + RtpPacketToSend::ExtensionManager extensions; + constexpr char kLongStreamId[] = "LoooooooooongRsid"; + ASSERT_EQ(strlen(kLongStreamId), 17u); + extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId); + RtpPacketToSend packet(&extensions); + EXPECT_FALSE(packet.SetExtension<RtpStreamId>(kLongStreamId)); +} + +TEST(RtpPacketTest, TryToCreateWithEmptyMid) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register<RtpMid>(kRtpMidExtensionId); + RtpPacketToSend packet(&extensions); + EXPECT_FALSE(packet.SetExtension<RtpMid>("")); +} + +TEST(RtpPacketTest, TryToCreateWithLongMid) { + RtpPacketToSend::ExtensionManager extensions; + constexpr char kLongMid[] = "LoooooooooonogMid"; + ASSERT_EQ(strlen(kLongMid), 17u); + extensions.Register<RtpMid>(kRtpMidExtensionId); + RtpPacketToSend packet(&extensions); + EXPECT_FALSE(packet.SetExtension<RtpMid>(kLongMid)); +} + +TEST(RtpPacketTest, CreateWithExtensionsWithoutManager) { + RtpPacketToSend packet(nullptr); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + + auto raw = packet.AllocateRawExtension(kTransmissionOffsetExtensionId, + TransmissionOffset::kValueSizeBytes); + EXPECT_EQ(raw.size(), TransmissionOffset::kValueSizeBytes); + TransmissionOffset::Write(raw.data(), kTimeOffset); + + raw = packet.AllocateRawExtension(kAudioLevelExtensionId, + AudioLevel::kValueSizeBytes); + EXPECT_EQ(raw.size(), AudioLevel::kValueSizeBytes); + AudioLevel::Write(raw.data(), kVoiceActive, kAudioLevel); + + EXPECT_THAT(kPacketWithTOAndAL, + ElementsAreArray(packet.data(), packet.size())); +} + +TEST(RtpPacketTest, CreateWithMaxSizeHeaderExtension) { + const size_t kMaxExtensionSize = 16; + const int kId = 1; + const uint8_t kValue[16] = "123456789abcdef"; + + // Write packet with a custom extension. + RtpPacketToSend packet(nullptr); + packet.SetRawExtension(kId, kValue); + // Using different size for same id is not allowed. + EXPECT_TRUE(packet.AllocateRawExtension(kId, kMaxExtensionSize - 1).empty()); + + packet.SetPayloadSize(42); + // Rewriting allocated extension is allowed. + EXPECT_EQ(packet.AllocateRawExtension(kId, kMaxExtensionSize).size(), + kMaxExtensionSize); + // Adding another extension after payload is set is not allowed. + EXPECT_TRUE(packet.AllocateRawExtension(kId + 1, kMaxExtensionSize).empty()); + + // Read packet with the custom extension. + RtpPacketReceived parsed; + EXPECT_TRUE(parsed.Parse(packet.Buffer())); + auto read_raw = parsed.GetRawExtension(kId); + EXPECT_THAT(read_raw, ElementsAreArray(kValue, kMaxExtensionSize)); +} + +TEST(RtpPacketTest, CreateWithDynamicSizedExtensionCsrcAudioLevel) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register<CsrcAudioLevel>(kCsrcAudioLevelExtensionId); + RtpPacketToSend packet(&extensions); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + CsrcAudioLevelList levels; + levels.numAudioLevels = kCsrcAudioLevelsSize; + for (uint8_t i = 0; i < kCsrcAudioLevelsSize; i++) { + levels.arrOfAudioLevels[i] = kCsrcAudioLevels[i]; + } + packet.SetExtension<CsrcAudioLevel>(levels); + EXPECT_THAT(kPacketWithCsrcAudioLevels, + ElementsAreArray(packet.data(), packet.size())); +} + +TEST(RtpPacketTest, SetReservedExtensionsAfterPayload) { + const size_t kPayloadSize = 4; + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId); + RtpPacketToSend packet(&extensions); + + EXPECT_TRUE(packet.ReserveExtension<TransmissionOffset>()); + packet.SetPayloadSize(kPayloadSize); + // Can't set extension after payload. + EXPECT_FALSE(packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel)); + // Unless reserved. + EXPECT_TRUE(packet.SetExtension<TransmissionOffset>(kTimeOffset)); +} + +TEST(RtpPacketTest, CreatePurePadding) { + const size_t kPaddingSize = kMaxPaddingSize - 1; + RtpPacketToSend packet(nullptr, 12 + kPaddingSize); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + Random random(0x123456789); + + EXPECT_LT(packet.size(), packet.capacity()); + EXPECT_FALSE(packet.SetPadding(kPaddingSize + 1, &random)); + EXPECT_TRUE(packet.SetPadding(kPaddingSize, &random)); + EXPECT_EQ(packet.size(), packet.capacity()); +} + +TEST(RtpPacketTest, CreateUnalignedPadding) { + const size_t kPayloadSize = 3; // Make padding start at unaligned address. + RtpPacketToSend packet(nullptr, 12 + kPayloadSize + kMaxPaddingSize); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + packet.SetPayloadSize(kPayloadSize); + Random r(0x123456789); + + EXPECT_LT(packet.size(), packet.capacity()); + EXPECT_TRUE(packet.SetPadding(kMaxPaddingSize, &r)); + EXPECT_EQ(packet.size(), packet.capacity()); +} + +TEST(RtpPacketTest, ParseMinimum) { + RtpPacketReceived packet; + EXPECT_TRUE(packet.Parse(kMinimumPacket, sizeof(kMinimumPacket))); + EXPECT_EQ(kPayloadType, packet.PayloadType()); + EXPECT_EQ(kSeqNum, packet.SequenceNumber()); + EXPECT_EQ(kTimestamp, packet.Timestamp()); + EXPECT_EQ(kSsrc, packet.Ssrc()); + EXPECT_EQ(0u, packet.padding_size()); + EXPECT_EQ(0u, packet.payload_size()); +} + +TEST(RtpPacketTest, ParseBuffer) { + rtc::CopyOnWriteBuffer unparsed(kMinimumPacket); + const uint8_t* raw = unparsed.data(); + + RtpPacketReceived packet; + EXPECT_TRUE(packet.Parse(std::move(unparsed))); + EXPECT_EQ(raw, packet.data()); // Expect packet take the buffer without copy. + EXPECT_EQ(kSeqNum, packet.SequenceNumber()); + EXPECT_EQ(kTimestamp, packet.Timestamp()); + EXPECT_EQ(kSsrc, packet.Ssrc()); + EXPECT_EQ(0u, packet.padding_size()); + EXPECT_EQ(0u, packet.payload_size()); +} + +TEST(RtpPacketTest, ParseWithExtension) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + + RtpPacketReceived packet(&extensions); + EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO))); + EXPECT_EQ(kPayloadType, packet.PayloadType()); + EXPECT_EQ(kSeqNum, packet.SequenceNumber()); + EXPECT_EQ(kTimestamp, packet.Timestamp()); + EXPECT_EQ(kSsrc, packet.Ssrc()); + int32_t time_offset; + EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset)); + EXPECT_EQ(kTimeOffset, time_offset); + EXPECT_EQ(0u, packet.payload_size()); + EXPECT_EQ(0u, packet.padding_size()); +} + +TEST(RtpPacketTest, ParseWithInvalidSizedExtension) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + + RtpPacketReceived packet(&extensions); + EXPECT_TRUE(packet.Parse(kPacketWithInvalidExtension, + sizeof(kPacketWithInvalidExtension))); + + // Extension should be ignored. + int32_t time_offset; + EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset)); + + // But shouldn't prevent reading payload. + EXPECT_THAT(packet.payload(), ElementsAreArray(kPayload)); +} + +TEST(RtpPacketTest, ParseWithOverSizedExtension) { + // clang-format off + const uint8_t bad_packet[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0xbe, 0xde, 0x00, 0x01, // Extension of size 1x32bit word. + 0x00, // Add a byte of padding. + 0x12, // Extension id 1 size (2+1). + 0xda, 0x1a // Only 2 bytes of extension payload. + }; + // clang-format on + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(TransmissionOffset::kId, 1); + RtpPacketReceived packet(&extensions); + + // Parse should ignore bad extension and proceed. + EXPECT_TRUE(packet.Parse(bad_packet, sizeof(bad_packet))); + int32_t time_offset; + // But extracting extension should fail. + EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset)); +} + +TEST(RtpPacketTest, ParseWith2Extensions) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId); + RtpPacketReceived packet(&extensions); + EXPECT_TRUE(packet.Parse(kPacketWithTOAndAL, sizeof(kPacketWithTOAndAL))); + int32_t time_offset; + EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset)); + EXPECT_EQ(kTimeOffset, time_offset); + bool voice_active; + uint8_t audio_level; + EXPECT_TRUE(packet.GetExtension<AudioLevel>(&voice_active, &audio_level)); + EXPECT_EQ(kVoiceActive, voice_active); + EXPECT_EQ(kAudioLevel, audio_level); +} + +TEST(RtpPacketTest, ParseWithAllFeatures) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + RtpPacketReceived packet(&extensions); + EXPECT_TRUE(packet.Parse(kPacket, sizeof(kPacket))); + EXPECT_EQ(kPayloadType, packet.PayloadType()); + EXPECT_EQ(kSeqNum, packet.SequenceNumber()); + EXPECT_EQ(kTimestamp, packet.Timestamp()); + EXPECT_EQ(kSsrc, packet.Ssrc()); + EXPECT_THAT(packet.Csrcs(), ElementsAreArray(kCsrcs)); + EXPECT_THAT(packet.payload(), ElementsAreArray(kPayload)); + EXPECT_EQ(kPacketPaddingSize, packet.padding_size()); + int32_t time_offset; + EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset)); +} + +TEST(RtpPacketTest, ParseWithExtensionDelayed) { + RtpPacketReceived packet; + EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO))); + EXPECT_EQ(kPayloadType, packet.PayloadType()); + EXPECT_EQ(kSeqNum, packet.SequenceNumber()); + EXPECT_EQ(kTimestamp, packet.Timestamp()); + EXPECT_EQ(kSsrc, packet.Ssrc()); + + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionOffsetExtensionId); + + int32_t time_offset; + EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset)); + packet.IdentifyExtensions(extensions); + EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset)); + EXPECT_EQ(kTimeOffset, time_offset); + EXPECT_EQ(0u, packet.payload_size()); + EXPECT_EQ(0u, packet.padding_size()); +} + +TEST(RtpPacketTest, ParseWithoutExtensionManager) { + RtpPacketReceived packet; + EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO))); + + EXPECT_FALSE(packet.HasRawExtension(kAudioLevelExtensionId)); + EXPECT_TRUE(packet.GetRawExtension(kAudioLevelExtensionId).empty()); + + EXPECT_TRUE(packet.HasRawExtension(kTransmissionOffsetExtensionId)); + + int32_t time_offset = 0; + auto raw_extension = packet.GetRawExtension(kTransmissionOffsetExtensionId); + EXPECT_EQ(raw_extension.size(), TransmissionOffset::kValueSizeBytes); + EXPECT_TRUE(TransmissionOffset::Parse(raw_extension, &time_offset)); + + EXPECT_EQ(time_offset, kTimeOffset); +} + +TEST(RtpPacketTest, ParseDynamicSizeExtension) { + // clang-format off + const uint8_t kPacket1[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, // Timestamp. + 0x12, 0x34, 0x56, 0x78, // Ssrc. + 0xbe, 0xde, 0x00, 0x02, // Extensions block of size 2x32bit words. + 0x21, 'H', 'D', // Extension with id = 2, size = (1+1). + 0x12, 'r', 't', 'x', // Extension with id = 1, size = (2+1). + 0x00}; // Extension padding. + const uint8_t kPacket2[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, // Timestamp. + 0x12, 0x34, 0x56, 0x79, // Ssrc. + 0xbe, 0xde, 0x00, 0x01, // Extensions block of size 1x32bit words. + 0x11, 'H', 'D', // Extension with id = 1, size = (1+1). + 0x00}; // Extension padding. + // clang-format on + RtpPacketReceived::ExtensionManager extensions; + extensions.Register<RtpStreamId>(1); + extensions.Register<RepairedRtpStreamId>(2); + RtpPacketReceived packet(&extensions); + ASSERT_TRUE(packet.Parse(kPacket1, sizeof(kPacket1))); + + std::string rsid; + EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid)); + EXPECT_EQ(rsid, "rtx"); + + std::string repaired_rsid; + EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid)); + EXPECT_EQ(repaired_rsid, "HD"); + + // Parse another packet with RtpStreamId extension of different size. + ASSERT_TRUE(packet.Parse(kPacket2, sizeof(kPacket2))); + EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid)); + EXPECT_EQ(rsid, "HD"); + EXPECT_FALSE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid)); +} + +TEST(RtpPacketTest, ParseWithMid) { + RtpPacketReceived::ExtensionManager extensions; + extensions.Register<RtpMid>(kRtpMidExtensionId); + RtpPacketReceived packet(&extensions); + ASSERT_TRUE(packet.Parse(kPacketWithMid, sizeof(kPacketWithMid))); + + std::string mid; + EXPECT_TRUE(packet.GetExtension<RtpMid>(&mid)); + EXPECT_EQ(mid, kMid); +} + +TEST(RtpPacketTest, RawExtensionFunctionsAcceptZeroIdAndReturnFalse) { + RtpPacketReceived::ExtensionManager extensions; + RtpPacketReceived packet(&extensions); + // Use ExtensionManager to set kInvalidId to 0 to demonstrate natural way for + // using zero value as a parameter to Packet::*RawExtension functions. + const int kInvalidId = extensions.GetId(TransmissionOffset::kId); + ASSERT_EQ(kInvalidId, 0); + + ASSERT_TRUE(packet.Parse(kPacket, sizeof(kPacket))); + + EXPECT_FALSE(packet.HasRawExtension(kInvalidId)); + EXPECT_THAT(packet.GetRawExtension(kInvalidId), IsEmpty()); + const uint8_t kExtension[] = {'e', 'x', 't'}; + EXPECT_FALSE(packet.SetRawExtension(kInvalidId, kExtension)); + EXPECT_THAT(packet.AllocateRawExtension(kInvalidId, 3), IsEmpty()); +} + +TEST(RtpPacketTest, CreateAndParseTimingFrameExtension) { + // Create a packet with video frame timing extension populated. + RtpPacketToSend::ExtensionManager send_extensions; + send_extensions.Register(kRtpExtensionVideoTiming, kVideoTimingExtensionId); + RtpPacketToSend send_packet(&send_extensions); + send_packet.SetPayloadType(kPayloadType); + send_packet.SetSequenceNumber(kSeqNum); + send_packet.SetTimestamp(kTimestamp); + send_packet.SetSsrc(kSsrc); + + VideoSendTiming timing; + timing.encode_start_delta_ms = 1; + timing.encode_finish_delta_ms = 2; + timing.packetization_finish_delta_ms = 3; + timing.pacer_exit_delta_ms = 4; + timing.flags = + TimingFrameFlags::kTriggeredByTimer + TimingFrameFlags::kTriggeredBySize; + + send_packet.SetExtension<VideoTimingExtension>(timing); + + // Serialize the packet and then parse it again. + RtpPacketReceived::ExtensionManager extensions; + extensions.Register<VideoTimingExtension>(kVideoTimingExtensionId); + RtpPacketReceived receive_packet(&extensions); + EXPECT_TRUE(receive_packet.Parse(send_packet.Buffer())); + + VideoSendTiming receivied_timing; + EXPECT_TRUE( + receive_packet.GetExtension<VideoTimingExtension>(&receivied_timing)); + + // Only check first and last timestamp (covered by other tests) plus flags. + EXPECT_EQ(receivied_timing.encode_start_delta_ms, + timing.encode_start_delta_ms); + EXPECT_EQ(receivied_timing.pacer_exit_delta_ms, timing.pacer_exit_delta_ms); + EXPECT_EQ(receivied_timing.flags, timing.flags); +} + +TEST(RtpPacketTest, ParseLegacyTimingFrameExtension) { + // Parse the modified packet. + RtpPacketReceived::ExtensionManager extensions; + extensions.Register<VideoTimingExtension>(kVideoTimingExtensionId); + RtpPacketReceived packet(&extensions); + EXPECT_TRUE(packet.Parse(kPacketWithLegacyTimingExtension, + sizeof(kPacketWithLegacyTimingExtension))); + VideoSendTiming receivied_timing; + EXPECT_TRUE(packet.GetExtension<VideoTimingExtension>(&receivied_timing)); + + // Check first and last timestamp are still OK. Flags should now be 0. + EXPECT_EQ(receivied_timing.encode_start_delta_ms, 1); + EXPECT_EQ(receivied_timing.pacer_exit_delta_ms, 4); + EXPECT_EQ(receivied_timing.flags, 0); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc new file mode 100644 index 0000000000..93e8a34836 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc @@ -0,0 +1,346 @@ +/* + * 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 "modules/rtp_rtcp/include/rtp_payload_registry.h" + +#include <algorithm> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/audio_coding/codecs/audio_format_conversion.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/stringutils.h" + +namespace webrtc { + +namespace { + +bool PayloadIsCompatible(const RtpUtility::Payload& payload, + const SdpAudioFormat& audio_format) { + return payload.typeSpecific.is_audio() && + audio_format.Matches(payload.typeSpecific.audio_payload().format); +} + +bool PayloadIsCompatible(const RtpUtility::Payload& payload, + const VideoCodec& video_codec) { + if (!payload.typeSpecific.is_video() || + _stricmp(payload.name, video_codec.plName) != 0) + return false; + // For H264, profiles must match as well. + if (video_codec.codecType == kVideoCodecH264) { + return video_codec.H264().profile == + payload.typeSpecific.video_payload().h264_profile; + } + return true; +} + +RtpUtility::Payload CreatePayloadType(const SdpAudioFormat& audio_format) { + RTC_DCHECK_GE(audio_format.clockrate_hz, 1000); + return {audio_format.name.c_str(), + PayloadUnion(AudioPayload{audio_format, 0})}; +} + +RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) { + switch (type) { + case kVideoCodecVP8: + return kRtpVideoVp8; + case kVideoCodecVP9: + return kRtpVideoVp9; + case kVideoCodecH264: + return kRtpVideoH264; + case kVideoCodecRED: + case kVideoCodecULPFEC: + return kRtpVideoNone; + default: + return kRtpVideoGeneric; + } +} + +RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) { + VideoPayload p; + p.videoCodecType = ConvertToRtpVideoCodecType(video_codec.codecType); + if (video_codec.codecType == kVideoCodecH264) + p.h264_profile = video_codec.H264().profile; + return {video_codec.plName, PayloadUnion(p)}; +} + +bool IsPayloadTypeValid(int8_t payload_type) { + assert(payload_type >= 0); + + // Sanity check. + switch (payload_type) { + // Reserved payload types to avoid RTCP conflicts when marker bit is set. + case 64: // 192 Full INTRA-frame request. + case 72: // 200 Sender report. + case 73: // 201 Receiver report. + case 74: // 202 Source description. + case 75: // 203 Goodbye. + case 76: // 204 Application-defined. + case 77: // 205 Transport layer FB message. + case 78: // 206 Payload-specific FB message. + case 79: // 207 Extended report. + RTC_LOG(LS_ERROR) << "Can't register invalid receiver payload type: " + << payload_type; + return false; + default: + return true; + } +} + +} // namespace + +RTPPayloadRegistry::RTPPayloadRegistry() + : incoming_payload_type_(-1), + last_received_payload_type_(-1), + last_received_media_payload_type_(-1), + rtx_(false), + ssrc_rtx_(0) {} + +RTPPayloadRegistry::~RTPPayloadRegistry() = default; + +void RTPPayloadRegistry::SetAudioReceivePayloads( + std::map<int, SdpAudioFormat> codecs) { + rtc::CritScope cs(&crit_sect_); + +#if RTC_DCHECK_IS_ON + RTC_DCHECK(!used_for_video_); + used_for_audio_ = true; +#endif + + payload_type_map_.clear(); + for (const auto& kv : codecs) { + const int& rtp_payload_type = kv.first; + const SdpAudioFormat& audio_format = kv.second; + RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type)); + payload_type_map_.emplace(rtp_payload_type, + CreatePayloadType(audio_format)); + } + + // Clear the value of last received payload type since it might mean + // something else now. + last_received_payload_type_ = -1; + last_received_media_payload_type_ = -1; +} + +int32_t RTPPayloadRegistry::RegisterReceivePayload( + int payload_type, + const SdpAudioFormat& audio_format, + bool* created_new_payload) { + rtc::CritScope cs(&crit_sect_); + +#if RTC_DCHECK_IS_ON + RTC_DCHECK(!used_for_video_); + used_for_audio_ = true; +#endif + + *created_new_payload = false; + if (!IsPayloadTypeValid(payload_type)) + return -1; + + const auto it = payload_type_map_.find(payload_type); + if (it != payload_type_map_.end()) { + // We already use this payload type. Check if it's the same as we already + // have. If same, ignore sending an error. + if (PayloadIsCompatible(it->second, audio_format)) { + it->second.typeSpecific.audio_payload().rate = 0; + return 0; + } + RTC_LOG(LS_ERROR) << "Payload type already registered: " << payload_type; + return -1; + } + + // Audio codecs must be unique. + DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_format); + + const auto insert_status = + payload_type_map_.emplace(payload_type, CreatePayloadType(audio_format)); + RTC_DCHECK(insert_status.second); // Insertion succeeded. + *created_new_payload = true; + + // Successful set of payload type, clear the value of last received payload + // type since it might mean something else. + last_received_payload_type_ = -1; + last_received_media_payload_type_ = -1; + return 0; +} + +int32_t RTPPayloadRegistry::RegisterReceivePayload( + const VideoCodec& video_codec) { + rtc::CritScope cs(&crit_sect_); + +#if RTC_DCHECK_IS_ON + RTC_DCHECK(!used_for_audio_); + used_for_video_ = true; +#endif + + if (!IsPayloadTypeValid(video_codec.plType)) + return -1; + + auto it = payload_type_map_.find(video_codec.plType); + if (it != payload_type_map_.end()) { + // We already use this payload type. Check if it's the same as we already + // have. If same, ignore sending an error. + if (PayloadIsCompatible(it->second, video_codec)) + return 0; + RTC_LOG(LS_ERROR) << "Payload type already registered: " + << static_cast<int>(video_codec.plType); + return -1; + } + + const auto insert_status = payload_type_map_.emplace( + video_codec.plType, CreatePayloadType(video_codec)); + RTC_DCHECK(insert_status.second); // Insertion succeeded. + + // Successful set of payload type, clear the value of last received payload + // type since it might mean something else. + last_received_payload_type_ = -1; + last_received_media_payload_type_ = -1; + return 0; +} + +int32_t RTPPayloadRegistry::DeRegisterReceivePayload( + const int8_t payload_type) { + rtc::CritScope cs(&crit_sect_); + payload_type_map_.erase(payload_type); + return 0; +} + +// There can't be several codecs with the same rate, frequency and channels +// for audio codecs, but there can for video. +// Always called from within a critical section. +void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( + const SdpAudioFormat& audio_format) { + for (auto iterator = payload_type_map_.begin(); + iterator != payload_type_map_.end(); ++iterator) { + if (PayloadIsCompatible(iterator->second, audio_format)) { + // Remove old setting. + payload_type_map_.erase(iterator); + break; + } + } +} + +int32_t RTPPayloadRegistry::ReceivePayloadType( + const SdpAudioFormat& audio_format, + int8_t* payload_type) const { + assert(payload_type); + rtc::CritScope cs(&crit_sect_); + + for (const auto& it : payload_type_map_) { + if (PayloadIsCompatible(it.second, audio_format)) { + *payload_type = it.first; + return 0; + } + } + return -1; +} + +int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_codec, + int8_t* payload_type) const { + assert(payload_type); + rtc::CritScope cs(&crit_sect_); + + for (const auto& it : payload_type_map_) { + if (PayloadIsCompatible(it.second, video_codec)) { + *payload_type = it.first; + return 0; + } + } + return -1; +} + +bool RTPPayloadRegistry::RtxEnabled() const { + rtc::CritScope cs(&crit_sect_); + return rtx_; +} + +bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const { + return rtx_ && ssrc_rtx_ == header.ssrc; +} + +void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) { + rtc::CritScope cs(&crit_sect_); + ssrc_rtx_ = ssrc; + rtx_ = true; +} + +bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const { + rtc::CritScope cs(&crit_sect_); + *ssrc = ssrc_rtx_; + return rtx_; +} + +void RTPPayloadRegistry::SetRtxPayloadType(int payload_type, + int associated_payload_type) { + rtc::CritScope cs(&crit_sect_); + if (payload_type < 0) { + RTC_LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type; + return; + } + + rtx_payload_type_map_[payload_type] = associated_payload_type; + rtx_ = true; +} + +bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const { + rtc::CritScope cs(&crit_sect_); + auto it = payload_type_map_.find(header.payloadType); + return it != payload_type_map_.end() && _stricmp(it->second.name, "red") == 0; +} + +int RTPPayloadRegistry::GetPayloadTypeFrequency( + uint8_t payload_type) const { + const auto payload = PayloadTypeToPayload(payload_type); + if (!payload) { + return -1; + } + rtc::CritScope cs(&crit_sect_); + return payload->typeSpecific.is_audio() + ? payload->typeSpecific.audio_payload().format.clockrate_hz + : kVideoPayloadTypeFrequency; +} + +rtc::Optional<RtpUtility::Payload> RTPPayloadRegistry::PayloadTypeToPayload( + uint8_t payload_type) const { + rtc::CritScope cs(&crit_sect_); + const auto it = payload_type_map_.find(payload_type); + return it == payload_type_map_.end() + ? rtc::nullopt + : rtc::Optional<RtpUtility::Payload>(it->second); +} + +void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) { + rtc::CritScope cs(&crit_sect_); + if (!IsRtxInternal(header)) + incoming_payload_type_ = header.payloadType; +} + +bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) { + rtc::CritScope cs(&crit_sect_); + if (last_received_media_payload_type_ == media_payload_type) { + // Media type unchanged. + return true; + } + last_received_media_payload_type_ = media_payload_type; + return false; +} + +// Returns -1 if a payload with name |payload_name| is not registered. +int8_t RTPPayloadRegistry::GetPayloadTypeWithName( + const char* payload_name) const { + rtc::CritScope cs(&crit_sect_); + for (const auto& it : payload_type_map_) { + if (_stricmp(it.second.name, payload_name) == 0) + return it.first; + } + return -1; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc new file mode 100644 index 0000000000..ee2c016d26 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc @@ -0,0 +1,226 @@ +/* + * 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 <memory> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "modules/rtp_rtcp/include/rtp_payload_registry.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +using ::testing::Eq; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::_; + +TEST(RtpPayloadRegistryTest, + RegistersAndRemembersVideoPayloadsUntilDeregistered) { + RTPPayloadRegistry rtp_payload_registry; + const uint8_t payload_type = 97; + VideoCodec video_codec; + video_codec.codecType = kVideoCodecVP8; + strncpy(video_codec.plName, "VP8", RTP_PAYLOAD_NAME_SIZE); + video_codec.plType = payload_type; + + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(video_codec)); + + const auto retrieved_payload = + rtp_payload_registry.PayloadTypeToPayload(payload_type); + EXPECT_TRUE(retrieved_payload); + + // We should get back the corresponding payload that we registered. + EXPECT_STREQ("VP8", retrieved_payload->name); + EXPECT_TRUE(retrieved_payload->typeSpecific.is_video()); + EXPECT_EQ(kRtpVideoVp8, + retrieved_payload->typeSpecific.video_payload().videoCodecType); + + // Now forget about it and verify it's gone. + EXPECT_EQ(0, rtp_payload_registry.DeRegisterReceivePayload(payload_type)); + EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type)); +} + +TEST(RtpPayloadRegistryTest, + RegistersAndRemembersAudioPayloadsUntilDeregistered) { + RTPPayloadRegistry rtp_payload_registry; + constexpr int payload_type = 97; + const SdpAudioFormat audio_format("name", 44000, 1); + bool new_payload_created = false; + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format, &new_payload_created)); + + EXPECT_TRUE(new_payload_created) << "A new payload WAS created."; + + const auto retrieved_payload = + rtp_payload_registry.PayloadTypeToPayload(payload_type); + EXPECT_TRUE(retrieved_payload); + + // We should get back the corresponding payload that we registered. + EXPECT_STREQ("name", retrieved_payload->name); + EXPECT_TRUE(retrieved_payload->typeSpecific.is_audio()); + EXPECT_EQ(audio_format, + retrieved_payload->typeSpecific.audio_payload().format); + + // Now forget about it and verify it's gone. + EXPECT_EQ(0, rtp_payload_registry.DeRegisterReceivePayload(payload_type)); + EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type)); +} + +TEST(RtpPayloadRegistryTest, AudioRedWorkProperly) { + RTPPayloadRegistry rtp_payload_registry; + bool new_payload_created = false; + const SdpAudioFormat red_format("red", 8000, 1); + + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + 127, red_format, &new_payload_created)); + EXPECT_TRUE(new_payload_created); + + EXPECT_EQ(127, rtp_payload_registry.red_payload_type()); + + const auto retrieved_payload = rtp_payload_registry.PayloadTypeToPayload(127); + EXPECT_TRUE(retrieved_payload); + EXPECT_TRUE(retrieved_payload->typeSpecific.is_audio()); + EXPECT_EQ(red_format, retrieved_payload->typeSpecific.audio_payload().format); +} + +TEST(RtpPayloadRegistryTest, + DoesNotAcceptSamePayloadTypeTwiceExceptIfPayloadIsCompatible) { + constexpr int payload_type = 97; + RTPPayloadRegistry rtp_payload_registry; + + bool ignored = false; + const SdpAudioFormat audio_format("name", 44000, 1); + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format, &ignored)); + + const SdpAudioFormat audio_format_2("name", 44001, 1); // Not compatible. + EXPECT_EQ(-1, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format_2, &ignored)) + << "Adding incompatible codec with same payload type = bad."; + + // Change payload type. + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type - 1, audio_format_2, &ignored)) + << "With a different payload type is fine though."; + + // Ensure both payloads are preserved. + const auto retrieved_payload1 = + rtp_payload_registry.PayloadTypeToPayload(payload_type); + EXPECT_TRUE(retrieved_payload1); + EXPECT_STREQ("name", retrieved_payload1->name); + EXPECT_TRUE(retrieved_payload1->typeSpecific.is_audio()); + EXPECT_EQ(audio_format, + retrieved_payload1->typeSpecific.audio_payload().format); + + const auto retrieved_payload2 = + rtp_payload_registry.PayloadTypeToPayload(payload_type - 1); + EXPECT_TRUE(retrieved_payload2); + EXPECT_STREQ("name", retrieved_payload2->name); + EXPECT_TRUE(retrieved_payload2->typeSpecific.is_audio()); + EXPECT_EQ(audio_format_2, + retrieved_payload2->typeSpecific.audio_payload().format); + + // Ok, update the rate for one of the codecs. If either the incoming rate or + // the stored rate is zero it's not really an error to register the same + // codec twice, and in that case roughly the following happens. + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format, &ignored)); +} + +TEST(RtpPayloadRegistryTest, + RemovesCompatibleCodecsOnRegistryIfCodecsMustBeUnique) { + constexpr int payload_type = 97; + RTPPayloadRegistry rtp_payload_registry; + + bool ignored = false; + const SdpAudioFormat audio_format("name", 44000, 1); + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format, &ignored)); + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type - 1, audio_format, &ignored)); + + EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type)) + << "The first payload should be " + "deregistered because the only thing that differs is payload type."; + EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type - 1)) + << "The second payload should still be registered though."; + + // Now ensure non-compatible codecs aren't removed. Make |audio_format_2| + // incompatible by changing the frequency. + const SdpAudioFormat audio_format_2("name", 44001, 1); + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type + 1, audio_format_2, &ignored)); + + EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type - 1)) + << "Not compatible; both payloads should be kept."; + EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type + 1)) + << "Not compatible; both payloads should be kept."; +} + +TEST(RtpPayloadRegistryTest, + LastReceivedCodecTypesAreResetWhenRegisteringNewPayloadTypes) { + RTPPayloadRegistry rtp_payload_registry; + rtp_payload_registry.set_last_received_payload_type(17); + EXPECT_EQ(17, rtp_payload_registry.last_received_payload_type()); + + bool media_type_unchanged = rtp_payload_registry.ReportMediaPayloadType(18); + EXPECT_FALSE(media_type_unchanged); + media_type_unchanged = rtp_payload_registry.ReportMediaPayloadType(18); + EXPECT_TRUE(media_type_unchanged); + + bool ignored; + constexpr int payload_type = 34; + const SdpAudioFormat audio_format("name", 44000, 1); + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format, &ignored)); + + EXPECT_EQ(-1, rtp_payload_registry.last_received_payload_type()); + media_type_unchanged = rtp_payload_registry.ReportMediaPayloadType(18); + EXPECT_FALSE(media_type_unchanged); +} + +class ParameterizedRtpPayloadRegistryTest + : public ::testing::TestWithParam<int> {}; + +TEST_P(ParameterizedRtpPayloadRegistryTest, + FailsToRegisterKnownPayloadsWeAreNotInterestedIn) { + RTPPayloadRegistry rtp_payload_registry; + + bool ignored; + const int payload_type = GetParam(); + const SdpAudioFormat audio_format("whatever", 1900, 1); + EXPECT_EQ(-1, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format, &ignored)); +} + +INSTANTIATE_TEST_CASE_P(TestKnownBadPayloadTypes, + ParameterizedRtpPayloadRegistryTest, + testing::Values(64, 72, 73, 74, 75, 76, 77, 78, 79)); + +class RtpPayloadRegistryGenericTest : public ::testing::TestWithParam<int> {}; + +TEST_P(RtpPayloadRegistryGenericTest, RegisterGenericReceivePayloadType) { + RTPPayloadRegistry rtp_payload_registry; + + bool ignored; + const int payload_type = GetParam(); + const SdpAudioFormat audio_format("generic-codec", 1900, 1); // Dummy values. + EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload( + payload_type, audio_format, &ignored)); +} + +INSTANTIATE_TEST_CASE_P(TestDynamicRange, + RtpPayloadRegistryGenericTest, + testing::Range(96, 127 + 1)); + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc new file mode 100644 index 0000000000..270c00d48a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc @@ -0,0 +1,308 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_receiver_audio.h" + +#include <assert.h> // assert +#include <math.h> // pow() +#include <string.h> // memcpy() + +#include "common_types.h" // NOLINT(build/include) +#include "rtc_base/logging.h" +#include "rtc_base/trace_event.h" + +namespace webrtc { +RTPReceiverStrategy* RTPReceiverStrategy::CreateAudioStrategy( + RtpData* data_callback) { + return new RTPReceiverAudio(data_callback); +} + +RTPReceiverAudio::RTPReceiverAudio(RtpData* data_callback) + : RTPReceiverStrategy(data_callback), + TelephoneEventHandler(), + telephone_event_forward_to_decoder_(false), + telephone_event_payload_type_(-1), + cng_nb_payload_type_(-1), + cng_wb_payload_type_(-1), + cng_swb_payload_type_(-1), + cng_fb_payload_type_(-1), + num_energy_(0), + current_remote_energy_() { + memset(current_remote_energy_, 0, sizeof(current_remote_energy_)); +} + +// Outband TelephoneEvent(DTMF) detection +void RTPReceiverAudio::SetTelephoneEventForwardToDecoder( + bool forward_to_decoder) { + rtc::CritScope lock(&crit_sect_); + telephone_event_forward_to_decoder_ = forward_to_decoder; +} + +// Is forwarding of outband telephone events turned on/off? +bool RTPReceiverAudio::TelephoneEventForwardToDecoder() const { + rtc::CritScope lock(&crit_sect_); + return telephone_event_forward_to_decoder_; +} + +bool RTPReceiverAudio::TelephoneEventPayloadType( + int8_t payload_type) const { + rtc::CritScope lock(&crit_sect_); + return telephone_event_payload_type_ == payload_type; +} + +bool RTPReceiverAudio::CNGPayloadType(int8_t payload_type) { + rtc::CritScope lock(&crit_sect_); + return payload_type == cng_nb_payload_type_ || + payload_type == cng_wb_payload_type_ || + payload_type == cng_swb_payload_type_ || + payload_type == cng_fb_payload_type_; +} + +bool RTPReceiverAudio::ShouldReportCsrcChanges(uint8_t payload_type) const { + // Don't do this for DTMF packets, otherwise it's fine. + return !TelephoneEventPayloadType(payload_type); +} + +// - Sample based or frame based codecs based on RFC 3551 +// - +// - NOTE! There is one error in the RFC, stating G.722 uses 8 bits/samples. +// - The correct rate is 4 bits/sample. +// - +// - name of sampling default +// - encoding sample/frame bits/sample rate ms/frame ms/packet +// - +// - Sample based audio codecs +// - DVI4 sample 4 var. 20 +// - G722 sample 4 16,000 20 +// - G726-40 sample 5 8,000 20 +// - G726-32 sample 4 8,000 20 +// - G726-24 sample 3 8,000 20 +// - G726-16 sample 2 8,000 20 +// - L8 sample 8 var. 20 +// - L16 sample 16 var. 20 +// - PCMA sample 8 var. 20 +// - PCMU sample 8 var. 20 +// - +// - Frame based audio codecs +// - G723 frame N/A 8,000 30 30 +// - G728 frame N/A 8,000 2.5 20 +// - G729 frame N/A 8,000 10 20 +// - G729D frame N/A 8,000 10 20 +// - G729E frame N/A 8,000 10 20 +// - GSM frame N/A 8,000 20 20 +// - GSM-EFR frame N/A 8,000 20 20 +// - LPC frame N/A 8,000 20 20 +// - MPA frame N/A var. var. +// - +// - G7221 frame N/A +int32_t RTPReceiverAudio::OnNewPayloadTypeCreated( + int payload_type, + const SdpAudioFormat& audio_format) { + rtc::CritScope lock(&crit_sect_); + + if (RtpUtility::StringCompare(audio_format.name.c_str(), "telephone-event", + 15)) { + telephone_event_payload_type_ = payload_type; + } + if (RtpUtility::StringCompare(audio_format.name.c_str(), "cn", 2)) { + // We support comfort noise at four different frequencies. + if (audio_format.clockrate_hz == 8000) { + cng_nb_payload_type_ = payload_type; + } else if (audio_format.clockrate_hz == 16000) { + cng_wb_payload_type_ = payload_type; + } else if (audio_format.clockrate_hz == 32000) { + cng_swb_payload_type_ = payload_type; + } else if (audio_format.clockrate_hz == 48000) { + cng_fb_payload_type_ = payload_type; + } else { + assert(false); + return -1; + } + } + return 0; +} + +int32_t RTPReceiverAudio::ParseRtpPacket(WebRtcRTPHeader* rtp_header, + const PayloadUnion& specific_payload, + bool is_red, + const uint8_t* payload, + size_t payload_length, + int64_t timestamp_ms) { + TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Audio::ParseRtp", + "seqnum", rtp_header->header.sequenceNumber, "timestamp", + rtp_header->header.timestamp); + rtp_header->type.Audio.numEnergy = rtp_header->header.numCSRCs; + num_energy_ = rtp_header->type.Audio.numEnergy; + if (rtp_header->type.Audio.numEnergy > 0 && + rtp_header->type.Audio.numEnergy <= kRtpCsrcSize) { + memcpy(current_remote_energy_, + rtp_header->type.Audio.arrOfEnergy, + rtp_header->type.Audio.numEnergy); + } + + if (first_packet_received_()) { + RTC_LOG(LS_INFO) << "Received first audio RTP packet"; + } + + return ParseAudioCodecSpecific(rtp_header, payload, payload_length, + specific_payload.audio_payload(), is_red); +} + +RTPAliveType RTPReceiverAudio::ProcessDeadOrAlive( + uint16_t last_payload_length) const { + + // Our CNG is 9 bytes; if it's a likely CNG the receiver needs to check + // kRtpNoRtp against NetEq speech_type kOutputPLCtoCNG. + if (last_payload_length < 10) { // our CNG is 9 bytes + return kRtpNoRtp; + } else { + return kRtpDead; + } +} + +void RTPReceiverAudio::CheckPayloadChanged(int8_t payload_type, + PayloadUnion* /* specific_payload */, + bool* should_discard_changes) { + *should_discard_changes = + TelephoneEventPayloadType(payload_type) || CNGPayloadType(payload_type); +} + +int RTPReceiverAudio::Energy(uint8_t array_of_energy[kRtpCsrcSize]) const { + rtc::CritScope cs(&crit_sect_); + + assert(num_energy_ <= kRtpCsrcSize); + + if (num_energy_ > 0) { + memcpy(array_of_energy, current_remote_energy_, + sizeof(uint8_t) * num_energy_); + } + return num_energy_; +} + +int32_t RTPReceiverAudio::InvokeOnInitializeDecoder( + RtpFeedback* callback, + int8_t payload_type, + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const PayloadUnion& specific_payload) const { + const auto& ap = specific_payload.audio_payload(); + if (callback->OnInitializeDecoder(payload_type, ap.format, ap.rate) == -1) { + RTC_LOG(LS_ERROR) << "Failed to create decoder for payload type: " + << payload_name << "/" << static_cast<int>(payload_type); + return -1; + } + return 0; +} + +// We are not allowed to have any critsects when calling data_callback. +int32_t RTPReceiverAudio::ParseAudioCodecSpecific( + WebRtcRTPHeader* rtp_header, + const uint8_t* payload_data, + size_t payload_length, + const AudioPayload& audio_specific, + bool is_red) { + RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength); + const size_t payload_data_length = + payload_length - rtp_header->header.paddingLength; + if (payload_data_length == 0) { + rtp_header->type.Audio.isCNG = false; + rtp_header->frameType = kEmptyFrame; + return data_callback_->OnReceivedPayloadData(nullptr, 0, rtp_header); + } + + bool telephone_event_packet = + TelephoneEventPayloadType(rtp_header->header.payloadType); + if (telephone_event_packet) { + rtc::CritScope lock(&crit_sect_); + + // RFC 4733 2.3 + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | event |E|R| volume | duration | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + if (payload_data_length % 4 != 0) { + return -1; + } + size_t number_of_events = payload_data_length / 4; + + // sanity + if (number_of_events >= MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS) { + number_of_events = MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS; + } + for (size_t n = 0; n < number_of_events; ++n) { + RTC_DCHECK_GE(payload_data_length, (4 * n) + 2); + bool end = (payload_data[(4 * n) + 1] & 0x80) ? true : false; + + std::set<uint8_t>::iterator event = + telephone_event_reported_.find(payload_data[4 * n]); + + if (event != telephone_event_reported_.end()) { + // we have already seen this event + if (end) { + telephone_event_reported_.erase(payload_data[4 * n]); + } + } else { + if (end) { + // don't add if it's a end of a tone + } else { + telephone_event_reported_.insert(payload_data[4 * n]); + } + } + } + + // RFC 4733 2.5.1.3 & 2.5.2.3 Long-Duration Events + // should not be a problem since we don't care about the duration + + // RFC 4733 See 2.5.1.5. & 2.5.2.4. Multiple Events in a Packet + } + + { + rtc::CritScope lock(&crit_sect_); + + // Check if this is a CNG packet, receiver might want to know + if (CNGPayloadType(rtp_header->header.payloadType)) { + rtp_header->type.Audio.isCNG = true; + rtp_header->frameType = kAudioFrameCN; + } else { + rtp_header->frameType = kAudioFrameSpeech; + rtp_header->type.Audio.isCNG = false; + } + + // check if it's a DTMF event, hence something we can playout + if (telephone_event_packet) { + if (!telephone_event_forward_to_decoder_) { + // don't forward event to decoder + return 0; + } + std::set<uint8_t>::iterator first = + telephone_event_reported_.begin(); + if (first != telephone_event_reported_.end() && *first > 15) { + // don't forward non DTMF events + return 0; + } + } + } + // TODO(holmer): Break this out to have RED parsing handled generically. + RTC_DCHECK_GT(payload_data_length, 0); + if (is_red && !(payload_data[0] & 0x80)) { + // we recive only one frame packed in a RED packet remove the RED wrapper + rtp_header->header.payloadType = payload_data[0]; + + // only one frame in the RED strip the one byte to help NetEq + return data_callback_->OnReceivedPayloadData( + payload_data + 1, payload_data_length - 1, rtp_header); + } + + rtp_header->type.Audio.channel = audio_specific.format.num_channels; + return data_callback_->OnReceivedPayloadData(payload_data, + payload_data_length, rtp_header); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h new file mode 100644 index 0000000000..b031002709 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h @@ -0,0 +1,98 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_ + +#include <set> + +#include "modules/rtp_rtcp/include/rtp_receiver.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/onetimeevent.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +// Handles audio RTP packets. This class is thread-safe. +class RTPReceiverAudio : public RTPReceiverStrategy, + public TelephoneEventHandler { + public: + explicit RTPReceiverAudio(RtpData* data_callback); + virtual ~RTPReceiverAudio() {} + + // The following three methods implement the TelephoneEventHandler interface. + // Forward DTMFs to decoder for playout. + void SetTelephoneEventForwardToDecoder(bool forward_to_decoder) override; + + // Is forwarding of outband telephone events turned on/off? + bool TelephoneEventForwardToDecoder() const override; + + // Is TelephoneEvent configured with |payload_type|. + bool TelephoneEventPayloadType(const int8_t payload_type) const override; + + TelephoneEventHandler* GetTelephoneEventHandler() override { return this; } + + // Returns true if CNG is configured with |payload_type|. + bool CNGPayloadType(const int8_t payload_type); + + int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header, + const PayloadUnion& specific_payload, + bool is_red, + const uint8_t* packet, + size_t payload_length, + int64_t timestamp_ms) override; + + RTPAliveType ProcessDeadOrAlive(uint16_t last_payload_length) const override; + + bool ShouldReportCsrcChanges(uint8_t payload_type) const override; + + int32_t OnNewPayloadTypeCreated(int payload_type, + const SdpAudioFormat& audio_format) override; + + int32_t InvokeOnInitializeDecoder( + RtpFeedback* callback, + int8_t payload_type, + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const PayloadUnion& specific_payload) const override; + + // We need to look out for special payload types here and sometimes reset + // statistics. In addition we sometimes need to tweak the frequency. + void CheckPayloadChanged(int8_t payload_type, + PayloadUnion* specific_payload, + bool* should_discard_changes) override; + + int Energy(uint8_t array_of_energy[kRtpCsrcSize]) const override; + + private: + int32_t ParseAudioCodecSpecific(WebRtcRTPHeader* rtp_header, + const uint8_t* payload_data, + size_t payload_length, + const AudioPayload& audio_specific, + bool is_red); + + bool telephone_event_forward_to_decoder_; + int8_t telephone_event_payload_type_; + std::set<uint8_t> telephone_event_reported_; + + int8_t cng_nb_payload_type_; + int8_t cng_wb_payload_type_; + int8_t cng_swb_payload_type_; + int8_t cng_fb_payload_type_; + + uint8_t num_energy_; + uint8_t current_remote_energy_[kRtpCsrcSize]; + + ThreadUnsafeOneTimeEvent first_packet_received_; +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc new file mode 100644 index 0000000000..0f084c3111 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc @@ -0,0 +1,573 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_receiver_impl.h" + +#include <assert.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include <set> +#include <vector> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/audio_coding/codecs/audio_format_conversion.h" +#include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/include/rtp_payload_registry.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +namespace { +bool InOrderPacket(const rtc::Optional<uint16_t>& latest_sequence_number, + uint16_t current_sequence_number) { + if (!latest_sequence_number) + return true; + + // We need to distinguish between a late or retransmitted packet, + // and a sequence number discontinuity. + if (IsNewerSequenceNumber(current_sequence_number, *latest_sequence_number)) { + return true; + } else { + // If we have a restart of the remote side this packet is still in order. + return !IsNewerSequenceNumber( + current_sequence_number, + *latest_sequence_number - kDefaultMaxReorderingThreshold); + } +} + +} // namespace + +using RtpUtility::Payload; + +// Only return the sources in the last 10 seconds. +const int64_t kGetSourcesTimeoutMs = 10000; + +RtpReceiver* RtpReceiver::CreateVideoReceiver( + Clock* clock, + RtpData* incoming_payload_callback, + RtpFeedback* incoming_messages_callback, + RTPPayloadRegistry* rtp_payload_registry) { + RTC_DCHECK(incoming_payload_callback != nullptr); + if (!incoming_messages_callback) + incoming_messages_callback = NullObjectRtpFeedback(); + return new RtpReceiverImpl( + clock, incoming_messages_callback, rtp_payload_registry, + RTPReceiverStrategy::CreateVideoStrategy(incoming_payload_callback)); +} + +RtpReceiver* RtpReceiver::CreateAudioReceiver( + Clock* clock, + RtpData* incoming_payload_callback, + RtpFeedback* incoming_messages_callback, + RTPPayloadRegistry* rtp_payload_registry) { + RTC_DCHECK(incoming_payload_callback != nullptr); + if (!incoming_messages_callback) + incoming_messages_callback = NullObjectRtpFeedback(); + return new RtpReceiverImpl( + clock, incoming_messages_callback, rtp_payload_registry, + RTPReceiverStrategy::CreateAudioStrategy(incoming_payload_callback)); +} + +int32_t RtpReceiver::RegisterReceivePayload(const CodecInst& audio_codec) { + return RegisterReceivePayload(audio_codec.pltype, + CodecInstToSdp(audio_codec)); +} + +RtpReceiverImpl::RtpReceiverImpl(Clock* clock, + RtpFeedback* incoming_messages_callback, + RTPPayloadRegistry* rtp_payload_registry, + RTPReceiverStrategy* rtp_media_receiver) + : clock_(clock), + rtp_payload_registry_(rtp_payload_registry), + rtp_media_receiver_(rtp_media_receiver), + cb_rtp_feedback_(incoming_messages_callback), + ssrc_(0), + num_csrcs_(0), + current_remote_csrc_(), + last_received_timestamp_(0), + last_received_frame_time_ms_(-1) { + assert(incoming_messages_callback); + + memset(current_remote_csrc_, 0, sizeof(current_remote_csrc_)); +} + +RtpReceiverImpl::~RtpReceiverImpl() { + for (int i = 0; i < num_csrcs_; ++i) { + cb_rtp_feedback_->OnIncomingCSRCChanged(current_remote_csrc_[i], false); + } +} + +int32_t RtpReceiverImpl::RegisterReceivePayload( + int payload_type, + const SdpAudioFormat& audio_format) { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + // TODO(phoglund): Try to streamline handling of the RED codec and some other + // cases which makes it necessary to keep track of whether we created a + // payload or not. + bool created_new_payload = false; + int32_t result = rtp_payload_registry_->RegisterReceivePayload( + payload_type, audio_format, &created_new_payload); + if (created_new_payload) { + if (rtp_media_receiver_->OnNewPayloadTypeCreated(payload_type, + audio_format) != 0) { + RTC_LOG(LS_ERROR) << "Failed to register payload: " << audio_format.name + << "/" << payload_type; + return -1; + } + } + return result; +} + +int32_t RtpReceiverImpl::RegisterReceivePayload(const VideoCodec& video_codec) { + rtc::CritScope lock(&critical_section_rtp_receiver_); + return rtp_payload_registry_->RegisterReceivePayload(video_codec); +} + +int32_t RtpReceiverImpl::DeRegisterReceivePayload( + const int8_t payload_type) { + rtc::CritScope lock(&critical_section_rtp_receiver_); + return rtp_payload_registry_->DeRegisterReceivePayload(payload_type); +} + +uint32_t RtpReceiverImpl::SSRC() const { + rtc::CritScope lock(&critical_section_rtp_receiver_); + return ssrc_; +} + +// Get remote CSRC. +int32_t RtpReceiverImpl::CSRCs(uint32_t array_of_csrcs[kRtpCsrcSize]) const { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + assert(num_csrcs_ <= kRtpCsrcSize); + + if (num_csrcs_ > 0) { + memcpy(array_of_csrcs, current_remote_csrc_, sizeof(uint32_t)*num_csrcs_); + } + return num_csrcs_; +} + +void RtpReceiverImpl::GetRID(char rtp_stream_id[256]) const { + rtc::CritScope lock(&critical_section_rtp_receiver_); + if (!rtp_stream_id_.empty()) { + strncpy(rtp_stream_id, rtp_stream_id_.data(), 256); + } else { + rtp_stream_id[0] = '\0'; + } +} + +int32_t RtpReceiverImpl::Energy( + uint8_t array_of_energy[kRtpCsrcSize]) const { + return rtp_media_receiver_->Energy(array_of_energy); +} + +bool RtpReceiverImpl::IncomingRtpPacket(const RTPHeader& rtp_header, + const uint8_t* payload, + size_t payload_length, + PayloadUnion payload_specific) { + // Trigger our callbacks. + CheckSSRCChanged(rtp_header); + + int8_t first_payload_byte = payload_length > 0 ? payload[0] : 0; + bool is_red = false; + + if (CheckPayloadChanged(rtp_header, first_payload_byte, &is_red, + &payload_specific) == -1) { + if (payload_length == 0) { + // OK, keep-alive packet. + return true; + } + RTC_LOG(LS_WARNING) << "Receiving invalid payload type."; + return false; + } + + WebRtcRTPHeader webrtc_rtp_header; + memset(&webrtc_rtp_header, 0, sizeof(webrtc_rtp_header)); + webrtc_rtp_header.header = rtp_header; + CheckCSRC(webrtc_rtp_header); + + auto audio_level = + rtp_header.extension.hasAudioLevel + ? rtc::Optional<uint8_t>(rtp_header.extension.audioLevel) + : rtc::nullopt; + UpdateSources(audio_level); + + int32_t ret_val = rtp_media_receiver_->ParseRtpPacket( + &webrtc_rtp_header, payload_specific, is_red, payload, payload_length, + clock_->TimeInMilliseconds()); + + if (ret_val < 0) { + return false; + } + + { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + // TODO(nisse): Do not rely on InOrderPacket for recovered packets, when + // packet is passed as RtpPacketReceived and that information is available. + // We should ideally never record timestamps for retransmitted or recovered + // packets. + if (InOrderPacket(last_received_sequence_number_, + rtp_header.sequenceNumber)) { + last_received_sequence_number_.emplace(rtp_header.sequenceNumber); + last_received_timestamp_ = rtp_header.timestamp; + last_received_frame_time_ms_ = clock_->TimeInMilliseconds(); + + // RID rarely if ever changes + if (!rtp_header.extension.stream_id.empty() && + (rtp_header.extension.stream_id != rtp_stream_id_)) { + rtp_stream_id_ = rtp_header.extension.stream_id; + RTC_LOG(LS_INFO) << "Received new RID value: " << rtp_stream_id_.data(); + } + } + } + + return true; +} + +TelephoneEventHandler* RtpReceiverImpl::GetTelephoneEventHandler() { + return rtp_media_receiver_->GetTelephoneEventHandler(); +} + +std::vector<RtpSource> RtpReceiverImpl::GetSources() const { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + int64_t now_ms = clock_->TimeInMilliseconds(); + std::vector<RtpSource> sources; + + RTC_DCHECK(std::is_sorted(ssrc_sources_.begin(), ssrc_sources_.end(), + [](const RtpSource& lhs, const RtpSource& rhs) { + return lhs.timestamp_ms() < rhs.timestamp_ms(); + })); + RTC_DCHECK(std::is_sorted(csrc_sources_.begin(), csrc_sources_.end(), + [](const RtpSource& lhs, const RtpSource& rhs) { + return lhs.timestamp_ms() < rhs.timestamp_ms(); + })); + + std::set<uint32_t> selected_ssrcs; + for (auto rit = ssrc_sources_.rbegin(); rit != ssrc_sources_.rend(); ++rit) { + if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) { + break; + } + if (selected_ssrcs.insert(rit->source_id()).second) { + sources.push_back(*rit); + } + } + + for (auto rit = csrc_sources_.rbegin(); rit != csrc_sources_.rend(); ++rit) { + if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) { + break; + } + sources.push_back(*rit); + } + return sources; +} + +bool RtpReceiverImpl::GetLatestTimestamps(uint32_t* timestamp, + int64_t* receive_time_ms) const { + rtc::CritScope lock(&critical_section_rtp_receiver_); + if (!last_received_sequence_number_) + return false; + + *timestamp = last_received_timestamp_; + *receive_time_ms = last_received_frame_time_ms_; + + return true; +} + +// Implementation note: must not hold critsect when called. +void RtpReceiverImpl::CheckSSRCChanged(const RTPHeader& rtp_header) { + bool new_ssrc = false; + rtc::Optional<AudioPayload> reinitialize_audio_payload; + + { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + int8_t last_received_payload_type = + rtp_payload_registry_->last_received_payload_type(); + if (ssrc_ != rtp_header.ssrc || + (last_received_payload_type == -1 && ssrc_ == 0)) { + // We need the payload_type_ to make the call if the remote SSRC is 0. + new_ssrc = true; + + last_received_timestamp_ = 0; + last_received_frame_time_ms_ = -1; + + // Do we have a SSRC? Then the stream is restarted. + if (ssrc_ != 0) { + // Do we have the same codec? Then re-initialize coder. + if (rtp_header.payloadType == last_received_payload_type) { + const auto payload = rtp_payload_registry_->PayloadTypeToPayload( + rtp_header.payloadType); + if (!payload) { + return; + } + if (payload->typeSpecific.is_audio()) { + reinitialize_audio_payload.emplace( + payload->typeSpecific.audio_payload()); + } else { + // OnInitializeDecoder() is only used for audio. + } + } + } + ssrc_ = rtp_header.ssrc; + } + } + + if (new_ssrc) { + // We need to get this to our RTCP sender and receiver. + // We need to do this outside critical section. + cb_rtp_feedback_->OnIncomingSSRCChanged(rtp_header.ssrc); + } + + if (reinitialize_audio_payload) { + if (-1 == cb_rtp_feedback_->OnInitializeDecoder( + rtp_header.payloadType, reinitialize_audio_payload->format, + reinitialize_audio_payload->rate)) { + // New stream, same codec. + RTC_LOG(LS_ERROR) << "Failed to create decoder for payload type: " + << static_cast<int>(rtp_header.payloadType); + } + } +} + +// Implementation note: must not hold critsect when called. +// TODO(phoglund): Move as much as possible of this code path into the media +// specific receivers. Basically this method goes through a lot of trouble to +// compute something which is only used by the media specific parts later. If +// this code path moves we can get rid of some of the rtp_receiver -> +// media_specific interface (such as CheckPayloadChange, possibly get/set +// last known payload). +int32_t RtpReceiverImpl::CheckPayloadChanged(const RTPHeader& rtp_header, + const int8_t first_payload_byte, + bool* is_red, + PayloadUnion* specific_payload) { + bool re_initialize_decoder = false; + + char payload_name[RTP_PAYLOAD_NAME_SIZE]; + int8_t payload_type = rtp_header.payloadType; + + { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + int8_t last_received_payload_type = + rtp_payload_registry_->last_received_payload_type(); + // TODO(holmer): Remove this code when RED parsing has been broken out from + // RtpReceiverAudio. + if (payload_type != last_received_payload_type) { + if (rtp_payload_registry_->red_payload_type() == payload_type) { + // Get the real codec payload type. + payload_type = first_payload_byte & 0x7f; + *is_red = true; + + if (rtp_payload_registry_->red_payload_type() == payload_type) { + // Invalid payload type, traced by caller. If we proceeded here, + // this would be set as |_last_received_payload_type|, and we would no + // longer catch corrupt packets at this level. + return -1; + } + + // When we receive RED we need to check the real payload type. + if (payload_type == last_received_payload_type) { + rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload); + return 0; + } + } + bool should_discard_changes = false; + + rtp_media_receiver_->CheckPayloadChanged( + payload_type, specific_payload, + &should_discard_changes); + + if (should_discard_changes) { + *is_red = false; + return 0; + } + + const auto payload = + rtp_payload_registry_->PayloadTypeToPayload(payload_type); + if (!payload) { + // Not a registered payload type. + return -1; + } + payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; + strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1); + + rtp_payload_registry_->set_last_received_payload_type(payload_type); + + re_initialize_decoder = true; + + rtp_media_receiver_->SetLastMediaSpecificPayload(payload->typeSpecific); + rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload); + + if (!payload->typeSpecific.is_audio()) { + bool media_type_unchanged = + rtp_payload_registry_->ReportMediaPayloadType(payload_type); + if (media_type_unchanged) { + // Only reset the decoder if the media codec type has changed. + re_initialize_decoder = false; + } + } + } else { + rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload); + *is_red = false; + } + } // End critsect. + + if (re_initialize_decoder) { + if (-1 == + rtp_media_receiver_->InvokeOnInitializeDecoder( + cb_rtp_feedback_, payload_type, payload_name, *specific_payload)) { + return -1; // Wrong payload type. + } + } + return 0; +} + +// Implementation note: must not hold critsect when called. +void RtpReceiverImpl::CheckCSRC(const WebRtcRTPHeader& rtp_header) { + int32_t num_csrcs_diff = 0; + uint32_t old_remote_csrc[kRtpCsrcSize]; + uint8_t old_num_csrcs = 0; + + { + rtc::CritScope lock(&critical_section_rtp_receiver_); + + if (!rtp_media_receiver_->ShouldReportCsrcChanges( + rtp_header.header.payloadType)) { + return; + } + old_num_csrcs = num_csrcs_; + if (old_num_csrcs > 0) { + // Make a copy of old. + memcpy(old_remote_csrc, current_remote_csrc_, + num_csrcs_ * sizeof(uint32_t)); + } + const uint8_t num_csrcs = rtp_header.header.numCSRCs; + if ((num_csrcs > 0) && (num_csrcs <= kRtpCsrcSize)) { + // Copy new. + memcpy(current_remote_csrc_, + rtp_header.header.arrOfCSRCs, + num_csrcs * sizeof(uint32_t)); + } + if (num_csrcs > 0 || old_num_csrcs > 0) { + num_csrcs_diff = num_csrcs - old_num_csrcs; + num_csrcs_ = num_csrcs; // Update stored CSRCs. + } else { + // No change. + return; + } + } // End critsect. + + bool have_called_callback = false; + // Search for new CSRC in old array. + for (uint8_t i = 0; i < rtp_header.header.numCSRCs; ++i) { + const uint32_t csrc = rtp_header.header.arrOfCSRCs[i]; + + bool found_match = false; + for (uint8_t j = 0; j < old_num_csrcs; ++j) { + if (csrc == old_remote_csrc[j]) { // old list + found_match = true; + break; + } + } + if (!found_match && csrc) { + // Didn't find it, report it as new. + have_called_callback = true; + cb_rtp_feedback_->OnIncomingCSRCChanged(csrc, true); + } + } + // Search for old CSRC in new array. + for (uint8_t i = 0; i < old_num_csrcs; ++i) { + const uint32_t csrc = old_remote_csrc[i]; + + bool found_match = false; + for (uint8_t j = 0; j < rtp_header.header.numCSRCs; ++j) { + if (csrc == rtp_header.header.arrOfCSRCs[j]) { + found_match = true; + break; + } + } + if (!found_match && csrc) { + // Did not find it, report as removed. + have_called_callback = true; + cb_rtp_feedback_->OnIncomingCSRCChanged(csrc, false); + } + } + if (!have_called_callback) { + // If the CSRC list contain non-unique entries we will end up here. + // Using CSRC 0 to signal this event, not interop safe, other + // implementations might have CSRC 0 as a valid value. + if (num_csrcs_diff > 0) { + cb_rtp_feedback_->OnIncomingCSRCChanged(0, true); + } else if (num_csrcs_diff < 0) { + cb_rtp_feedback_->OnIncomingCSRCChanged(0, false); + } + } +} + +void RtpReceiverImpl::UpdateSources( + const rtc::Optional<uint8_t>& ssrc_audio_level) { + rtc::CritScope lock(&critical_section_rtp_receiver_); + int64_t now_ms = clock_->TimeInMilliseconds(); + + for (size_t i = 0; i < num_csrcs_; ++i) { + auto map_it = iterator_by_csrc_.find(current_remote_csrc_[i]); + if (map_it == iterator_by_csrc_.end()) { + // If it is a new CSRC, append a new object to the end of the list. + csrc_sources_.emplace_back(now_ms, current_remote_csrc_[i], + RtpSourceType::CSRC); + } else { + // If it is an existing CSRC, move the object to the end of the list. + map_it->second->update_timestamp_ms(now_ms); + csrc_sources_.splice(csrc_sources_.end(), csrc_sources_, map_it->second); + } + // Update the unordered_map. + iterator_by_csrc_[current_remote_csrc_[i]] = std::prev(csrc_sources_.end()); + } + + // If this is the first packet or the SSRC is changed, insert a new + // contributing source that uses the SSRC. + if (ssrc_sources_.empty() || ssrc_sources_.rbegin()->source_id() != ssrc_) { + ssrc_sources_.emplace_back(now_ms, ssrc_, RtpSourceType::SSRC); + } else { + ssrc_sources_.rbegin()->update_timestamp_ms(now_ms); + } + + ssrc_sources_.back().set_audio_level(ssrc_audio_level); + + RemoveOutdatedSources(now_ms); +} + +void RtpReceiverImpl::RemoveOutdatedSources(int64_t now_ms) { + std::list<RtpSource>::iterator it; + for (it = csrc_sources_.begin(); it != csrc_sources_.end(); ++it) { + if ((now_ms - it->timestamp_ms()) <= kGetSourcesTimeoutMs) { + break; + } + iterator_by_csrc_.erase(it->source_id()); + } + csrc_sources_.erase(csrc_sources_.begin(), it); + + std::vector<RtpSource>::iterator vec_it; + for (vec_it = ssrc_sources_.begin(); vec_it != ssrc_sources_.end(); + ++vec_it) { + if ((now_ms - vec_it->timestamp_ms()) <= kGetSourcesTimeoutMs) { + break; + } + } + ssrc_sources_.erase(ssrc_sources_.begin(), vec_it); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h new file mode 100644 index 0000000000..e412513c0f --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h @@ -0,0 +1,117 @@ +/* + * 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. + */ + +#ifndef MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_ + +#include <list> +#include <memory> +#include <unordered_map> +#include <vector> + +#include "api/optional.h" +#include "modules/rtp_rtcp/include/rtp_receiver.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h" +#include "rtc_base/criticalsection.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class RtpReceiverImpl : public RtpReceiver { + public: + // Callbacks passed in here may not be NULL (use Null Object callbacks if you + // want callbacks to do nothing). This class takes ownership of the media + // receiver but nothing else. + RtpReceiverImpl(Clock* clock, + RtpFeedback* incoming_messages_callback, + RTPPayloadRegistry* rtp_payload_registry, + RTPReceiverStrategy* rtp_media_receiver); + + virtual ~RtpReceiverImpl(); + + int32_t RegisterReceivePayload(int payload_type, + const SdpAudioFormat& audio_format) override; + int32_t RegisterReceivePayload(const VideoCodec& video_codec) override; + + int32_t DeRegisterReceivePayload(const int8_t payload_type) override; + + bool IncomingRtpPacket(const RTPHeader& rtp_header, + const uint8_t* payload, + size_t payload_length, + PayloadUnion payload_specific) override; + + bool GetLatestTimestamps(uint32_t* timestamp, + int64_t* receive_time_ms) const override; + + uint32_t SSRC() const override; + + int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const override; + + void GetRID(char rtp_stream_id[256]) const override; + + int32_t Energy(uint8_t array_of_energy[kRtpCsrcSize]) const override; + + TelephoneEventHandler* GetTelephoneEventHandler() override; + + std::vector<RtpSource> GetSources() const override; + + const std::vector<RtpSource>& ssrc_sources_for_testing() const { + return ssrc_sources_; + } + + const std::list<RtpSource>& csrc_sources_for_testing() const { + return csrc_sources_; + } + + private: + void CheckSSRCChanged(const RTPHeader& rtp_header); + void CheckCSRC(const WebRtcRTPHeader& rtp_header); + int32_t CheckPayloadChanged(const RTPHeader& rtp_header, + const int8_t first_payload_byte, + bool* is_red, + PayloadUnion* payload); + + void UpdateSources(const rtc::Optional<uint8_t>& ssrc_audio_level); + void RemoveOutdatedSources(int64_t now_ms); + + Clock* clock_; + rtc::CriticalSection critical_section_rtp_receiver_; + + RTPPayloadRegistry* const rtp_payload_registry_ + RTC_PT_GUARDED_BY(critical_section_rtp_receiver_); + const std::unique_ptr<RTPReceiverStrategy> rtp_media_receiver_; + + RtpFeedback* const cb_rtp_feedback_; + + // SSRCs. + uint32_t ssrc_ RTC_GUARDED_BY(critical_section_rtp_receiver_); + uint8_t num_csrcs_ RTC_GUARDED_BY(critical_section_rtp_receiver_); + uint32_t current_remote_csrc_[kRtpCsrcSize] RTC_GUARDED_BY( + critical_section_rtp_receiver_); + + // Sequence number and timestamps for the latest in-order packet. + rtc::Optional<uint16_t> last_received_sequence_number_ + RTC_GUARDED_BY(critical_section_rtp_receiver_); + uint32_t last_received_timestamp_ + RTC_GUARDED_BY(critical_section_rtp_receiver_); + int64_t last_received_frame_time_ms_ + RTC_GUARDED_BY(critical_section_rtp_receiver_); + StreamId rtp_stream_id_ + RTC_GUARDED_BY(critical_section_rtp_receiver_); + + std::unordered_map<uint32_t, std::list<RtpSource>::iterator> + iterator_by_csrc_; + // The RtpSource objects are sorted chronologically. + std::list<RtpSource> csrc_sources_; + std::vector<RtpSource> ssrc_sources_; +}; +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.cc new file mode 100644 index 0000000000..6db24c9a02 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.cc @@ -0,0 +1,45 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_receiver_strategy.h" + +#include <stdlib.h> + +namespace webrtc { + +RTPReceiverStrategy::RTPReceiverStrategy(RtpData* data_callback) + : data_callback_(data_callback) {} + +void RTPReceiverStrategy::GetLastMediaSpecificPayload( + PayloadUnion* payload) const { + rtc::CritScope cs(&crit_sect_); + if (last_payload_) { + *payload = *last_payload_; + } +} + +void RTPReceiverStrategy::SetLastMediaSpecificPayload( + const PayloadUnion& payload) { + rtc::CritScope cs(&crit_sect_); + last_payload_.emplace(payload); +} + +void RTPReceiverStrategy::CheckPayloadChanged(int8_t payload_type, + PayloadUnion* specific_payload, + bool* should_discard_changes) { + // Default: Keep changes. + *should_discard_changes = false; +} + +int RTPReceiverStrategy::Energy(uint8_t array_of_energy[kRtpCsrcSize]) const { + return -1; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h new file mode 100644 index 0000000000..3288329977 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h @@ -0,0 +1,99 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_ + +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/criticalsection.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +struct CodecInst; + +class TelephoneEventHandler; + +// This strategy deals with media-specific RTP packet processing. +// This class is not thread-safe and must be protected by its caller. +class RTPReceiverStrategy { + public: + static RTPReceiverStrategy* CreateVideoStrategy(RtpData* data_callback); + static RTPReceiverStrategy* CreateAudioStrategy(RtpData* data_callback); + + virtual ~RTPReceiverStrategy() {} + + // Parses the RTP packet and calls the data callback with the payload data. + // Implementations are encouraged to use the provided packet buffer and RTP + // header as arguments to the callback; implementations are also allowed to + // make changes in the data as necessary. The specific_payload argument + // provides audio or video-specific data. + virtual int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header, + const PayloadUnion& specific_payload, + bool is_red, + const uint8_t* payload, + size_t payload_length, + int64_t timestamp_ms) = 0; + + virtual TelephoneEventHandler* GetTelephoneEventHandler() = 0; + + // Computes the current dead-or-alive state. + virtual RTPAliveType ProcessDeadOrAlive( + uint16_t last_payload_length) const = 0; + + // Returns true if we should report CSRC changes for this payload type. + // TODO(phoglund): should move out of here along with other payload stuff. + virtual bool ShouldReportCsrcChanges(uint8_t payload_type) const = 0; + + // Notifies the strategy that we have created a new non-RED audio payload type + // in the payload registry. + virtual int32_t OnNewPayloadTypeCreated( + int payload_type, + const SdpAudioFormat& audio_format) = 0; + + // Invokes the OnInitializeDecoder callback in a media-specific way. + virtual int32_t InvokeOnInitializeDecoder( + RtpFeedback* callback, + int8_t payload_type, + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const PayloadUnion& specific_payload) const = 0; + + // Checks if the payload type has changed, and returns whether we should + // reset statistics and/or discard this packet. + virtual void CheckPayloadChanged(int8_t payload_type, + PayloadUnion* specific_payload, + bool* should_discard_changes); + + virtual int Energy(uint8_t array_of_energy[kRtpCsrcSize]) const; + + // Stores / retrieves the last media specific payload for later reference. + void GetLastMediaSpecificPayload(PayloadUnion* payload) const; + void SetLastMediaSpecificPayload(const PayloadUnion& payload); + + protected: + // The data callback is where we should send received payload data. + // See ParseRtpPacket. This class does not claim ownership of the callback. + // Implementations must NOT hold any critical sections while calling the + // callback. + // + // Note: Implementations may call the callback for other reasons than calls + // to ParseRtpPacket, for instance if the implementation somehow recovers a + // packet. + explicit RTPReceiverStrategy(RtpData* data_callback); + + rtc::CriticalSection crit_sect_; + rtc::Optional<PayloadUnion> last_payload_; + RtpData* data_callback_; +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc new file mode 100644 index 0000000000..3d23b50c50 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2017 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 <memory> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "modules/rtp_rtcp/include/rtp_payload_registry.h" +#include "modules/rtp_rtcp/include/rtp_receiver.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" +#include "modules/rtp_rtcp/source/rtp_receiver_impl.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::NiceMock; +using ::testing::UnorderedElementsAre; + +const uint32_t kTestRate = 64000u; +const uint8_t kTestPayload[] = {'t', 'e', 's', 't'}; +const uint8_t kPcmuPayloadType = 96; +const int64_t kGetSourcesTimeoutMs = 10000; +const uint32_t kSsrc1 = 123; +const uint32_t kSsrc2 = 124; +const uint32_t kCsrc1 = 111; +const uint32_t kCsrc2 = 222; + +static uint32_t rtp_timestamp(int64_t time_ms) { + return static_cast<uint32_t>(time_ms * kTestRate / 1000); +} + +} // namespace + +class RtpReceiverTest : public ::testing::Test { + protected: + RtpReceiverTest() + : fake_clock_(123456), + rtp_receiver_( + RtpReceiver::CreateAudioReceiver(&fake_clock_, + &mock_rtp_data_, + nullptr, + &rtp_payload_registry_)) { + rtp_receiver_->RegisterReceivePayload(kPcmuPayloadType, + SdpAudioFormat("PCMU", 8000, 1)); + } + ~RtpReceiverTest() {} + + bool FindSourceByIdAndType(const std::vector<RtpSource>& sources, + uint32_t source_id, + RtpSourceType type, + RtpSource* source) { + for (size_t i = 0; i < sources.size(); ++i) { + if (sources[i].source_id() == source_id && + sources[i].source_type() == type) { + (*source) = sources[i]; + return true; + } + } + return false; + } + + SimulatedClock fake_clock_; + NiceMock<MockRtpData> mock_rtp_data_; + RTPPayloadRegistry rtp_payload_registry_; + std::unique_ptr<RtpReceiver> rtp_receiver_; +}; + +TEST_F(RtpReceiverTest, GetSources) { + int64_t now_ms = fake_clock_.TimeInMilliseconds(); + + RTPHeader header; + header.payloadType = kPcmuPayloadType; + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(now_ms); + header.numCSRCs = 2; + header.arrOfCSRCs[0] = kCsrc1; + header.arrOfCSRCs[1] = kCsrc2; + const PayloadUnion payload_specific{ + AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}}; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + auto sources = rtp_receiver_->GetSources(); + // One SSRC source and two CSRC sources. + EXPECT_THAT(sources, UnorderedElementsAre( + RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC), + RtpSource(now_ms, kCsrc1, RtpSourceType::CSRC), + RtpSource(now_ms, kCsrc2, RtpSourceType::CSRC))); + + // Advance the fake clock and the method is expected to return the + // contributing source object with same source id and updated timestamp. + fake_clock_.AdvanceTimeMilliseconds(1); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + sources = rtp_receiver_->GetSources(); + now_ms = fake_clock_.TimeInMilliseconds(); + EXPECT_THAT(sources, UnorderedElementsAre( + RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC), + RtpSource(now_ms, kCsrc1, RtpSourceType::CSRC), + RtpSource(now_ms, kCsrc2, RtpSourceType::CSRC))); + + // Test the edge case that the sources are still there just before the + // timeout. + int64_t prev_time_ms = fake_clock_.TimeInMilliseconds(); + fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs); + sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, + UnorderedElementsAre( + RtpSource(prev_time_ms, kSsrc1, RtpSourceType::SSRC), + RtpSource(prev_time_ms, kCsrc1, RtpSourceType::CSRC), + RtpSource(prev_time_ms, kCsrc2, RtpSourceType::CSRC))); + + // Time out. + fake_clock_.AdvanceTimeMilliseconds(1); + sources = rtp_receiver_->GetSources(); + // All the sources should be out of date. + ASSERT_EQ(0u, sources.size()); +} + +// Test the case that the SSRC is changed. +TEST_F(RtpReceiverTest, GetSourcesChangeSSRC) { + int64_t prev_time_ms = -1; + int64_t now_ms = fake_clock_.TimeInMilliseconds(); + + RTPHeader header; + header.payloadType = kPcmuPayloadType; + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(now_ms); + const PayloadUnion payload_specific{ + AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}}; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + auto sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, UnorderedElementsAre( + RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC))); + + // The SSRC is changed and the old SSRC is expected to be returned. + fake_clock_.AdvanceTimeMilliseconds(100); + prev_time_ms = now_ms; + now_ms = fake_clock_.TimeInMilliseconds(); + header.ssrc = kSsrc2; + header.timestamp = rtp_timestamp(now_ms); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, UnorderedElementsAre( + RtpSource(prev_time_ms, kSsrc1, RtpSourceType::SSRC), + RtpSource(now_ms, kSsrc2, RtpSourceType::SSRC))); + + // The SSRC is changed again and happen to be changed back to 1. No + // duplication is expected. + fake_clock_.AdvanceTimeMilliseconds(100); + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(now_ms); + prev_time_ms = now_ms; + now_ms = fake_clock_.TimeInMilliseconds(); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, UnorderedElementsAre( + RtpSource(prev_time_ms, kSsrc2, RtpSourceType::SSRC), + RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC))); + + // Old SSRC source timeout. + fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs); + now_ms = fake_clock_.TimeInMilliseconds(); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, UnorderedElementsAre( + RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC))); +} + +TEST_F(RtpReceiverTest, GetSourcesRemoveOutdatedSource) { + int64_t now_ms = fake_clock_.TimeInMilliseconds(); + + RTPHeader header; + header.payloadType = kPcmuPayloadType; + header.timestamp = rtp_timestamp(now_ms); + const PayloadUnion payload_specific{ + AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}}; + header.numCSRCs = 1; + size_t kSourceListSize = 20; + + for (size_t i = 0; i < kSourceListSize; ++i) { + header.ssrc = i; + header.arrOfCSRCs[0] = (i + 1); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + } + + RtpSource source(0, 0, RtpSourceType::SSRC); + auto sources = rtp_receiver_->GetSources(); + // Expect |kSourceListSize| SSRC sources and |kSourceListSize| CSRC sources. + ASSERT_EQ(2 * kSourceListSize, sources.size()); + for (size_t i = 0; i < kSourceListSize; ++i) { + // The SSRC source IDs are expected to be 19, 18, 17 ... 0 + ASSERT_TRUE( + FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source)); + EXPECT_EQ(now_ms, source.timestamp_ms()); + + // The CSRC source IDs are expected to be 20, 19, 18 ... 1 + ASSERT_TRUE( + FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source)); + EXPECT_EQ(now_ms, source.timestamp_ms()); + } + + fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs); + for (size_t i = 0; i < kSourceListSize; ++i) { + // The SSRC source IDs are expected to be 19, 18, 17 ... 0 + ASSERT_TRUE( + FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source)); + EXPECT_EQ(now_ms, source.timestamp_ms()); + + // The CSRC source IDs are expected to be 20, 19, 18 ... 1 + ASSERT_TRUE( + FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source)); + EXPECT_EQ(now_ms, source.timestamp_ms()); + } + + // Timeout. All the existing objects are out of date and are expected to be + // removed. + fake_clock_.AdvanceTimeMilliseconds(1); + header.ssrc = kSsrc1; + header.arrOfCSRCs[0] = kCsrc1; + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + auto rtp_receiver_impl = static_cast<RtpReceiverImpl*>(rtp_receiver_.get()); + auto ssrc_sources = rtp_receiver_impl->ssrc_sources_for_testing(); + ASSERT_EQ(1u, ssrc_sources.size()); + EXPECT_EQ(kSsrc1, ssrc_sources.begin()->source_id()); + EXPECT_EQ(RtpSourceType::SSRC, ssrc_sources.begin()->source_type()); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), + ssrc_sources.begin()->timestamp_ms()); + + auto csrc_sources = rtp_receiver_impl->csrc_sources_for_testing(); + ASSERT_EQ(1u, csrc_sources.size()); + EXPECT_EQ(kCsrc1, csrc_sources.begin()->source_id()); + EXPECT_EQ(RtpSourceType::CSRC, csrc_sources.begin()->source_type()); + EXPECT_EQ(fake_clock_.TimeInMilliseconds(), + csrc_sources.begin()->timestamp_ms()); +} + +// The audio level from the RTPHeader extension should be stored in the +// RtpSource with the matching SSRC. +TEST_F(RtpReceiverTest, GetSourcesContainsAudioLevelExtension) { + RTPHeader header; + int64_t time1_ms = fake_clock_.TimeInMilliseconds(); + header.payloadType = kPcmuPayloadType; + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(time1_ms); + header.extension.hasAudioLevel = true; + header.extension.audioLevel = 10; + const PayloadUnion payload_specific{ + AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}}; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + auto sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, UnorderedElementsAre(RtpSource( + time1_ms, kSsrc1, RtpSourceType::SSRC, 10))); + + // Receive a packet from a different SSRC with a different level and check + // that they are both remembered. + fake_clock_.AdvanceTimeMilliseconds(1); + int64_t time2_ms = fake_clock_.TimeInMilliseconds(); + header.ssrc = kSsrc2; + header.timestamp = rtp_timestamp(time2_ms); + header.extension.hasAudioLevel = true; + header.extension.audioLevel = 20; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, + UnorderedElementsAre( + RtpSource(time1_ms, kSsrc1, RtpSourceType::SSRC, 10), + RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20))); + + // Receive a packet from the first SSRC again and check that the level is + // updated. + fake_clock_.AdvanceTimeMilliseconds(1); + int64_t time3_ms = fake_clock_.TimeInMilliseconds(); + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(time3_ms); + header.extension.hasAudioLevel = true; + header.extension.audioLevel = 30; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, + UnorderedElementsAre( + RtpSource(time3_ms, kSsrc1, RtpSourceType::SSRC, 30), + RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20))); +} + +TEST_F(RtpReceiverTest, + MissingAudioLevelHeaderExtensionClearsRtpSourceAudioLevel) { + RTPHeader header; + int64_t time1_ms = fake_clock_.TimeInMilliseconds(); + header.payloadType = kPcmuPayloadType; + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(time1_ms); + header.extension.hasAudioLevel = true; + header.extension.audioLevel = 10; + const PayloadUnion payload_specific{ + AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}}; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + auto sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, UnorderedElementsAre(RtpSource( + time1_ms, kSsrc1, RtpSourceType::SSRC, 10))); + + // Receive a second packet without the audio level header extension and check + // that the audio level is cleared. + fake_clock_.AdvanceTimeMilliseconds(1); + int64_t time2_ms = fake_clock_.TimeInMilliseconds(); + header.timestamp = rtp_timestamp(time2_ms); + header.extension.hasAudioLevel = false; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + sources = rtp_receiver_->GetSources(); + EXPECT_THAT(sources, UnorderedElementsAre( + RtpSource(time2_ms, kSsrc1, RtpSourceType::SSRC))); +} + +TEST_F(RtpReceiverTest, UpdatesTimestampsIfAndOnlyIfPacketArrivesInOrder) { + RTPHeader header; + int64_t time1_ms = fake_clock_.TimeInMilliseconds(); + header.payloadType = kPcmuPayloadType; + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(time1_ms); + header.extension.hasAudioLevel = true; + header.extension.audioLevel = 10; + header.sequenceNumber = 0xfff0; + + const PayloadUnion payload_specific{ + AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}}; + uint32_t latest_timestamp; + int64_t latest_receive_time_ms; + + // No packet received yet. + EXPECT_FALSE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + // Initial packet + const uint32_t timestamp_1 = header.timestamp; + const int64_t receive_time_1 = fake_clock_.TimeInMilliseconds(); + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + EXPECT_EQ(latest_timestamp, timestamp_1); + EXPECT_EQ(latest_receive_time_ms, receive_time_1); + + // Late packet, timestamp not recorded. + fake_clock_.AdvanceTimeMilliseconds(10); + header.timestamp -= 900; + header.sequenceNumber -= 2; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + EXPECT_EQ(latest_timestamp, timestamp_1); + EXPECT_EQ(latest_receive_time_ms, receive_time_1); + + // New packet, still late, no wraparound. + fake_clock_.AdvanceTimeMilliseconds(10); + header.timestamp += 1800; + header.sequenceNumber += 1; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + EXPECT_EQ(latest_timestamp, timestamp_1); + EXPECT_EQ(latest_receive_time_ms, receive_time_1); + + // New packet, new timestamp recorded + fake_clock_.AdvanceTimeMilliseconds(10); + header.timestamp += 900; + header.sequenceNumber += 2; + const uint32_t timestamp_2 = header.timestamp; + const int64_t receive_time_2 = fake_clock_.TimeInMilliseconds(); + const uint16_t seqno_2 = header.sequenceNumber; + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + EXPECT_EQ(latest_timestamp, timestamp_2); + EXPECT_EQ(latest_receive_time_ms, receive_time_2); + + // New packet, timestamp wraps around + fake_clock_.AdvanceTimeMilliseconds(10); + header.timestamp += 900; + header.sequenceNumber += 20; + const uint32_t timestamp_3 = header.timestamp; + const int64_t receive_time_3 = fake_clock_.TimeInMilliseconds(); + EXPECT_LT(header.sequenceNumber, seqno_2); // Wrap-around + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + EXPECT_EQ(latest_timestamp, timestamp_3); + EXPECT_EQ(latest_receive_time_ms, receive_time_3); +} + +TEST_F(RtpReceiverTest, UpdatesTimestampsWhenStreamResets) { + RTPHeader header; + int64_t time1_ms = fake_clock_.TimeInMilliseconds(); + header.payloadType = kPcmuPayloadType; + header.ssrc = kSsrc1; + header.timestamp = rtp_timestamp(time1_ms); + header.extension.hasAudioLevel = true; + header.extension.audioLevel = 10; + header.sequenceNumber = 0xfff0; + + const PayloadUnion payload_specific{ + AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}}; + uint32_t latest_timestamp; + int64_t latest_receive_time_ms; + + // No packet received yet. + EXPECT_FALSE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + // Initial packet + const uint32_t timestamp_1 = header.timestamp; + const int64_t receive_time_1 = fake_clock_.TimeInMilliseconds(); + const uint16_t seqno_1 = header.sequenceNumber; + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + EXPECT_EQ(latest_timestamp, timestamp_1); + EXPECT_EQ(latest_receive_time_ms, receive_time_1); + + // Packet with far in the past seqno, but unlikely to be a wrap-around. + // Treated as a seqno discontinuity, and timestamp is recorded. + fake_clock_.AdvanceTimeMilliseconds(10); + header.timestamp += 900; + header.sequenceNumber = 0x9000; + + const uint32_t timestamp_2 = header.timestamp; + const int64_t receive_time_2 = fake_clock_.TimeInMilliseconds(); + const uint16_t seqno_2 = header.sequenceNumber; + EXPECT_LT(seqno_1 - seqno_2, 0x8000); // In the past. + + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, kTestPayload, sizeof(kTestPayload), payload_specific)); + EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp, + &latest_receive_time_ms)); + EXPECT_EQ(latest_timestamp, timestamp_2); + EXPECT_EQ(latest_receive_time_ms, receive_time_2); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc new file mode 100644 index 0000000000..65d1831e8d --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc @@ -0,0 +1,137 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_receiver_video.h" + +#include <assert.h> +#include <string.h> + +#include <memory> + +#include "modules/rtp_rtcp/include/rtp_cvo.h" +#include "modules/rtp_rtcp/include/rtp_payload_registry.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "modules/rtp_rtcp/source/rtp_format_video_generic.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/trace_event.h" + +namespace webrtc { + +RTPReceiverStrategy* RTPReceiverStrategy::CreateVideoStrategy( + RtpData* data_callback) { + return new RTPReceiverVideo(data_callback); +} + +RTPReceiverVideo::RTPReceiverVideo(RtpData* data_callback) + : RTPReceiverStrategy(data_callback) { +} + +RTPReceiverVideo::~RTPReceiverVideo() { +} + +bool RTPReceiverVideo::ShouldReportCsrcChanges(uint8_t payload_type) const { + // Always do this for video packets. + return true; +} + +int32_t RTPReceiverVideo::OnNewPayloadTypeCreated( + int payload_type, + const SdpAudioFormat& audio_format) { + RTC_NOTREACHED(); + return 0; +} + +int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header, + const PayloadUnion& specific_payload, + bool is_red, + const uint8_t* payload, + size_t payload_length, + int64_t timestamp_ms) { + TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Video::ParseRtp", + "seqnum", rtp_header->header.sequenceNumber, "timestamp", + rtp_header->header.timestamp); + rtp_header->type.Video.codec = + specific_payload.video_payload().videoCodecType; + + RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength); + const size_t payload_data_length = + payload_length - rtp_header->header.paddingLength; + + if (payload == NULL || payload_data_length == 0) { + return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0 + : -1; + } + + if (first_packet_received_()) { + RTC_LOG(LS_INFO) << "Received first video RTP packet"; + } + + // We are not allowed to hold a critical section when calling below functions. + std::unique_ptr<RtpDepacketizer> depacketizer( + RtpDepacketizer::Create(rtp_header->type.Video.codec)); + if (depacketizer.get() == NULL) { + RTC_LOG(LS_ERROR) << "Failed to create depacketizer."; + return -1; + } + + RtpDepacketizer::ParsedPayload parsed_payload; + if (!depacketizer->Parse(&parsed_payload, payload, payload_data_length)) + return -1; + + rtp_header->frameType = parsed_payload.frame_type; + rtp_header->type = parsed_payload.type; + rtp_header->type.Video.rotation = kVideoRotation_0; + rtp_header->type.Video.content_type = VideoContentType::UNSPECIFIED; + rtp_header->type.Video.video_timing.flags = TimingFrameFlags::kInvalid; + + // Retrieve the video rotation information. + if (rtp_header->header.extension.hasVideoRotation) { + rtp_header->type.Video.rotation = + rtp_header->header.extension.videoRotation; + } + + if (rtp_header->header.extension.hasVideoContentType) { + rtp_header->type.Video.content_type = + rtp_header->header.extension.videoContentType; + } + + if (rtp_header->header.extension.has_video_timing) { + rtp_header->type.Video.video_timing = + rtp_header->header.extension.video_timing; + } + + rtp_header->type.Video.playout_delay = + rtp_header->header.extension.playout_delay; + + return data_callback_->OnReceivedPayloadData(parsed_payload.payload, + parsed_payload.payload_length, + rtp_header) == 0 + ? 0 + : -1; +} + +RTPAliveType RTPReceiverVideo::ProcessDeadOrAlive( + uint16_t last_payload_length) const { + return kRtpDead; +} + +int32_t RTPReceiverVideo::InvokeOnInitializeDecoder( + RtpFeedback* callback, + int8_t payload_type, + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const PayloadUnion& specific_payload) const { + // TODO(pbos): Remove as soon as audio can handle a changing payload type + // without this callback. + return 0; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h new file mode 100644 index 0000000000..f1e14f4d40 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h @@ -0,0 +1,57 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_ + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/onetimeevent.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class RTPReceiverVideo : public RTPReceiverStrategy { + public: + explicit RTPReceiverVideo(RtpData* data_callback); + + virtual ~RTPReceiverVideo(); + + int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header, + const PayloadUnion& specific_payload, + bool is_red, + const uint8_t* packet, + size_t packet_length, + int64_t timestamp) override; + + TelephoneEventHandler* GetTelephoneEventHandler() override { return NULL; } + + RTPAliveType ProcessDeadOrAlive(uint16_t last_payload_length) const override; + + bool ShouldReportCsrcChanges(uint8_t payload_type) const override; + + int32_t OnNewPayloadTypeCreated(int payload_type, + const SdpAudioFormat& audio_format) override; + + int32_t InvokeOnInitializeDecoder( + RtpFeedback* callback, + int8_t payload_type, + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const PayloadUnion& specific_payload) const override; + + void SetPacketOverHead(uint16_t packet_over_head); + + private: + OneTimeEvent first_packet_received_; +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h new file mode 100644 index 0000000000..2333547ec3 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h @@ -0,0 +1,46 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_RTCP_CONFIG_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_RTCP_CONFIG_H_ + +// Configuration file for RTP utilities (RTPSender, RTPReceiver ...) +namespace webrtc { +enum { NACK_BYTECOUNT_SIZE = 60 }; // size of our NACK history +// A sanity for the NACK list parsing at the send-side. +enum { kSendSideNackListSizeSanity = 20000 }; +enum { kDefaultMaxReorderingThreshold = 50 }; // In sequence numbers. +enum { kRtcpMaxNackFields = 253 }; + +enum { RTCP_INTERVAL_VIDEO_MS = 1000 }; +enum { RTCP_INTERVAL_AUDIO_MS = 5000 }; +enum { RTCP_INTERVAL_RAPID_SYNC_MS = 100 }; // RFX 6051 +enum { RTCP_SEND_BEFORE_KEY_FRAME_MS = 100 }; +enum { RTCP_MAX_REPORT_BLOCKS = 31 }; // RFC 3550 page 37 +enum { + kRtcpAppCode_DATA_SIZE = 32 * 4 +}; // multiple of 4, this is not a limitation of the size +enum { RTCP_NUMBER_OF_SR = 60 }; + +enum { MAX_NUMBER_OF_TEMPORAL_ID = 8 }; // RFC +enum { MAX_NUMBER_OF_DEPENDENCY_QUALITY_ID = 128 }; // RFC +enum { MAX_NUMBER_OF_REMB_FEEDBACK_SSRCS = 255 }; + +enum { BW_HISTORY_SIZE = 35 }; + +#define MIN_AUDIO_BW_MANAGEMENT_BITRATE 6 +#define MIN_VIDEO_BW_MANAGEMENT_BITRATE 30 + +enum { RTP_MAX_BURST_SLEEP_TIME = 500 }; +enum { RTP_AUDIO_LEVEL_UNIQUE_ID = 0xbede }; +enum { RTP_MAX_PACKETS_PER_FRAME = 512 }; // must be multiple of 32 +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_RTCP_CONFIG_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc new file mode 100644 index 0000000000..a7e6109e31 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -0,0 +1,963 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_rtcp_impl.h" + +#include <string.h> + +#include <algorithm> +#include <set> +#include <string> + +#include "api/rtpparameters.h" +#include "common_types.h" // NOLINT(build/include) +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +#ifdef _WIN32 +// Disable warning C4355: 'this' : used in base member initializer list. +#pragma warning(disable : 4355) +#endif + +namespace webrtc { +namespace { +const int64_t kRtpRtcpMaxIdleTimeProcessMs = 5; +const int64_t kRtpRtcpRttProcessTimeMs = 1000; +const int64_t kRtpRtcpBitrateProcessTimeMs = 10; +const int64_t kDefaultExpectedRetransmissionTimeMs = 125; +} // namespace + +RTPExtensionType StringToRtpExtensionType(const std::string& extension) { + if (extension == RtpExtension::kTimestampOffsetUri) + return kRtpExtensionTransmissionTimeOffset; + if (extension == RtpExtension::kAudioLevelUri) + return kRtpExtensionAudioLevel; + if (extension == RtpExtension::kAbsSendTimeUri) + return kRtpExtensionAbsoluteSendTime; + if (extension == RtpExtension::kVideoRotationUri) + return kRtpExtensionVideoRotation; + if (extension == RtpExtension::kTransportSequenceNumberUri) + return kRtpExtensionTransportSequenceNumber; + if (extension == RtpExtension::kPlayoutDelayUri) + return kRtpExtensionPlayoutDelay; + if (extension == RtpExtension::kVideoContentTypeUri) + return kRtpExtensionVideoContentType; + if (extension == RtpExtension::kVideoTimingUri) + return kRtpExtensionVideoTiming; + if (extension == RtpExtension::kRtpStreamIdUri) + return kRtpExtensionRtpStreamId; + if (extension == RtpExtension::kRepairedRtpStreamIdUri) + return kRtpExtensionRepairedRtpStreamId; + if (extension == RtpExtension::kMIdUri) + return kRtpExtensionMid; + if (extension == RtpExtension::kCsrcAudioLevelUri) + return kRtpExtensionCsrcAudioLevel; + + RTC_NOTREACHED() << "Looking up unsupported RTP extension."; + return kRtpExtensionNone; +} + +RtpRtcp::Configuration::Configuration() = default; + +RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) { + if (configuration.clock) { + return new ModuleRtpRtcpImpl(configuration); + } else { + // No clock implementation provided, use default clock. + RtpRtcp::Configuration configuration_copy; + memcpy(&configuration_copy, &configuration, + sizeof(RtpRtcp::Configuration)); + configuration_copy.clock = Clock::GetRealTimeClock(); + return new ModuleRtpRtcpImpl(configuration_copy); + } +} + +// Deprecated. +int32_t RtpRtcp::SetFecParameters(const FecProtectionParams* delta_params, + const FecProtectionParams* key_params) { + RTC_DCHECK(delta_params); + RTC_DCHECK(key_params); + return SetFecParameters(*delta_params, *key_params) ? 0 : -1; +} + +ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) + : rtcp_sender_(configuration.audio, + configuration.clock, + configuration.receive_statistics, + configuration.rtcp_packet_type_counter_observer, + configuration.event_log, + configuration.outgoing_transport), + rtcp_receiver_(configuration.clock, + configuration.receiver_only, + configuration.rtcp_packet_type_counter_observer, + configuration.bandwidth_callback, + configuration.event_callback, + configuration.intra_frame_callback, + configuration.transport_feedback_callback, + configuration.bitrate_allocation_observer, + this), + clock_(configuration.clock), + audio_(configuration.audio), + keepalive_config_(configuration.keepalive_config), + last_bitrate_process_time_(clock_->TimeInMilliseconds()), + last_rtt_process_time_(clock_->TimeInMilliseconds()), + next_process_time_(clock_->TimeInMilliseconds() + + kRtpRtcpMaxIdleTimeProcessMs), + next_keepalive_time_(-1), + packet_overhead_(28), // IPV4 UDP. + nack_last_time_sent_full_(0), + nack_last_time_sent_full_prev_(0), + nack_last_seq_number_sent_(0), + key_frame_req_method_(kKeyFrameReqPliRtcp), + remote_bitrate_(configuration.remote_bitrate_estimator), + rtt_stats_(configuration.rtt_stats), + rtt_ms_(0) { + if (!configuration.receiver_only) { + rtp_sender_.reset(new RTPSender( + configuration.audio, + configuration.clock, + configuration.outgoing_transport, + configuration.paced_sender, + configuration.flexfec_sender, + configuration.transport_sequence_number_allocator, + configuration.transport_feedback_callback, + configuration.send_bitrate_observer, + configuration.send_frame_count_observer, + configuration.send_side_delay_observer, + configuration.event_log, + configuration.send_packet_observer, + configuration.retransmission_rate_limiter, + configuration.overhead_observer)); + // Make sure rtcp sender use same timestamp offset as rtp sender. + rtcp_sender_.SetTimestampOffset(rtp_sender_->TimestampOffset()); + + if (keepalive_config_.timeout_interval_ms != -1) { + next_keepalive_time_ = + clock_->TimeInMilliseconds() + keepalive_config_.timeout_interval_ms; + } + } + + // Set default packet size limit. + // TODO(nisse): Kind-of duplicates + // webrtc::VideoSendStream::Config::Rtp::kDefaultMaxPacketSize. + const size_t kTcpOverIpv4HeaderSize = 40; + SetMaxRtpPacketSize(IP_PACKET_SIZE - kTcpOverIpv4HeaderSize); +} + +// Returns the number of milliseconds until the module want a worker thread +// to call Process. +int64_t ModuleRtpRtcpImpl::TimeUntilNextProcess() { + return std::max<int64_t>(0, + next_process_time_ - clock_->TimeInMilliseconds()); +} + +// Process any pending tasks such as timeouts (non time critical events). +void ModuleRtpRtcpImpl::Process() { + const int64_t now = clock_->TimeInMilliseconds(); + next_process_time_ = now + kRtpRtcpMaxIdleTimeProcessMs; + + if (rtp_sender_) { + if (now >= last_bitrate_process_time_ + kRtpRtcpBitrateProcessTimeMs) { + rtp_sender_->ProcessBitrate(); + last_bitrate_process_time_ = now; + next_process_time_ = + std::min(next_process_time_, now + kRtpRtcpBitrateProcessTimeMs); + } + if (keepalive_config_.timeout_interval_ms > 0 && + now >= next_keepalive_time_) { + int64_t last_send_time_ms = rtp_sender_->LastTimestampTimeMs(); + // If no packet has been sent, |last_send_time_ms| will be 0, and so the + // keep-alive will be triggered as expected. + if (now >= last_send_time_ms + keepalive_config_.timeout_interval_ms) { + rtp_sender_->SendKeepAlive(keepalive_config_.payload_type); + next_keepalive_time_ = now + keepalive_config_.timeout_interval_ms; + } else { + next_keepalive_time_ = + last_send_time_ms + keepalive_config_.timeout_interval_ms; + } + next_process_time_ = std::min(next_process_time_, next_keepalive_time_); + } + } + + bool process_rtt = now >= last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs; + if (rtcp_sender_.Sending()) { + // Process RTT if we have received a report block and we haven't + // processed RTT for at least |kRtpRtcpRttProcessTimeMs| milliseconds. + if (rtcp_receiver_.LastReceivedReportBlockMs() > last_rtt_process_time_ && + process_rtt) { + std::vector<RTCPReportBlock> receive_blocks; + rtcp_receiver_.StatisticsReceived(&receive_blocks); + int64_t max_rtt = 0; + for (std::vector<RTCPReportBlock>::iterator it = receive_blocks.begin(); + it != receive_blocks.end(); ++it) { + int64_t rtt = 0; + rtcp_receiver_.RTT(it->sender_ssrc, &rtt, NULL, NULL, NULL); + max_rtt = (rtt > max_rtt) ? rtt : max_rtt; + } + // Report the rtt. + if (rtt_stats_ && max_rtt != 0) + rtt_stats_->OnRttUpdate(max_rtt); + } + + // Verify receiver reports are delivered and the reported sequence number + // is increasing. + int64_t rtcp_interval = RtcpReportInterval(); + if (rtcp_receiver_.RtcpRrTimeout(rtcp_interval)) { + RTC_LOG_F(LS_WARNING) << "Timeout: No RTCP RR received."; + } else if (rtcp_receiver_.RtcpRrSequenceNumberTimeout(rtcp_interval)) { + RTC_LOG_F(LS_WARNING) << "Timeout: No increase in RTCP RR extended " + "highest sequence number."; + } + + if (remote_bitrate_ && rtcp_sender_.TMMBR()) { + unsigned int target_bitrate = 0; + std::vector<unsigned int> ssrcs; + if (remote_bitrate_->LatestEstimate(&ssrcs, &target_bitrate)) { + if (!ssrcs.empty()) { + target_bitrate = target_bitrate / ssrcs.size(); + } + rtcp_sender_.SetTargetBitrate(target_bitrate); + } + } + } else { + // Report rtt from receiver. + if (process_rtt) { + int64_t rtt_ms; + if (rtt_stats_ && rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)) { + rtt_stats_->OnRttUpdate(rtt_ms); + } + } + } + + // Get processed rtt. + if (process_rtt) { + last_rtt_process_time_ = now; + next_process_time_ = std::min( + next_process_time_, last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs); + if (rtt_stats_) { + // Make sure we have a valid RTT before setting. + int64_t last_rtt = rtt_stats_->LastProcessedRtt(); + if (last_rtt >= 0) + set_rtt_ms(last_rtt); + } + } + + if (rtcp_sender_.TimeToSendRTCPReport()) + rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport); + + if (TMMBR() && rtcp_receiver_.UpdateTmmbrTimers()) { + rtcp_receiver_.NotifyTmmbrUpdated(); + } +} + +void ModuleRtpRtcpImpl::SetRtxSendStatus(int mode) { + rtp_sender_->SetRtxStatus(mode); +} + +int ModuleRtpRtcpImpl::RtxSendStatus() const { + return rtp_sender_ ? rtp_sender_->RtxStatus() : kRtxOff; +} + +void ModuleRtpRtcpImpl::SetRtxSsrc(uint32_t ssrc) { + rtp_sender_->SetRtxSsrc(ssrc); +} + +void ModuleRtpRtcpImpl::SetRtxSendPayloadType(int payload_type, + int associated_payload_type) { + rtp_sender_->SetRtxPayloadType(payload_type, associated_payload_type); +} + +rtc::Optional<uint32_t> ModuleRtpRtcpImpl::FlexfecSsrc() const { + if (rtp_sender_) + return rtp_sender_->FlexfecSsrc(); + return rtc::nullopt; +} + +void ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet, + const size_t length) { + rtcp_receiver_.IncomingPacket(rtcp_packet, length); +} + +int32_t ModuleRtpRtcpImpl::RegisterSendPayload( + const CodecInst& voice_codec) { + return rtp_sender_->RegisterPayload( + voice_codec.plname, voice_codec.pltype, voice_codec.plfreq, + voice_codec.channels, (voice_codec.rate < 0) ? 0 : voice_codec.rate); +} + +int32_t ModuleRtpRtcpImpl::RegisterSendPayload(const VideoCodec& video_codec) { + return rtp_sender_->RegisterPayload(video_codec.plName, video_codec.plType, + 90000, 0, 0); +} + +void ModuleRtpRtcpImpl::RegisterVideoSendPayload(int payload_type, + const char* payload_name) { + RTC_CHECK_EQ( + 0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, 0, 0)); +} + +int32_t ModuleRtpRtcpImpl::DeRegisterSendPayload(const int8_t payload_type) { + return rtp_sender_->DeRegisterSendPayload(payload_type); +} + +uint32_t ModuleRtpRtcpImpl::StartTimestamp() const { + return rtp_sender_->TimestampOffset(); +} + +// Configure start timestamp, default is a random number. +void ModuleRtpRtcpImpl::SetStartTimestamp(const uint32_t timestamp) { + rtcp_sender_.SetTimestampOffset(timestamp); + rtp_sender_->SetTimestampOffset(timestamp); +} + +uint16_t ModuleRtpRtcpImpl::SequenceNumber() const { + return rtp_sender_->SequenceNumber(); +} + +// Set SequenceNumber, default is a random number. +void ModuleRtpRtcpImpl::SetSequenceNumber(const uint16_t seq_num) { + rtp_sender_->SetSequenceNumber(seq_num); +} + +void ModuleRtpRtcpImpl::SetRtpState(const RtpState& rtp_state) { + rtp_sender_->SetRtpState(rtp_state); + rtcp_sender_.SetTimestampOffset(rtp_state.start_timestamp); +} + +void ModuleRtpRtcpImpl::SetRtxState(const RtpState& rtp_state) { + rtp_sender_->SetRtxRtpState(rtp_state); +} + +RtpState ModuleRtpRtcpImpl::GetRtpState() const { + return rtp_sender_->GetRtpState(); +} + +RtpState ModuleRtpRtcpImpl::GetRtxState() const { + return rtp_sender_->GetRtxRtpState(); +} + +uint32_t ModuleRtpRtcpImpl::SSRC() const { + return rtcp_sender_.SSRC(); +} + +void ModuleRtpRtcpImpl::SetSSRC(const uint32_t ssrc) { + if (rtp_sender_) { + rtp_sender_->SetSSRC(ssrc); + } + rtcp_sender_.SetSSRC(ssrc); + SetRtcpReceiverSsrcs(ssrc); +} + +void ModuleRtpRtcpImpl::SetCsrcs(const std::vector<uint32_t>& csrcs) { + rtcp_sender_.SetCsrcs(csrcs); + rtp_sender_->SetCsrcs(csrcs); +} + +int32_t ModuleRtpRtcpImpl::SetRID(const char *rid) { + //XXX rtcp_sender_.SetRID(rid); + return rtp_sender_->SetRID(rid); +} + +int32_t ModuleRtpRtcpImpl::SetMID(const char *mid) { + return rtp_sender_->SetMId(mid); +} + +// TODO(pbos): Handle media and RTX streams separately (separate RTCP +// feedbacks). +RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState() { + RTCPSender::FeedbackState state; + // This is called also when receiver_only is true. Hence below + // checks that rtp_sender_ exists. + if (rtp_sender_) { + StreamDataCounters rtp_stats; + StreamDataCounters rtx_stats; + rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats); + state.packets_sent = rtp_stats.transmitted.packets + + rtx_stats.transmitted.packets; + state.media_bytes_sent = rtp_stats.transmitted.payload_bytes + + rtx_stats.transmitted.payload_bytes; + state.send_bitrate = rtp_sender_->BitrateSent(); + } + state.module = this; + + LastReceivedNTP(&state.last_rr_ntp_secs, + &state.last_rr_ntp_frac, + &state.remote_sr); + + state.has_last_xr_rr = + rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&state.last_xr_rr); + + return state; +} + +// TODO(nisse): This method shouldn't be called for a receive-only +// stream. Delete rtp_sender_ check as soon as all applications are +// updated. +int32_t ModuleRtpRtcpImpl::SetSendingStatus(const bool sending) { + if (rtcp_sender_.Sending() != sending) { + // Sends RTCP BYE when going from true to false + if (rtcp_sender_.SetSendingStatus(GetFeedbackState(), sending) != 0) { + RTC_LOG(LS_WARNING) << "Failed to send RTCP BYE"; + } + if (sending && rtp_sender_) { + // Update Rtcp receiver config, to track Rtx config changes from + // the SetRtxStatus and SetRtxSsrc methods. + SetRtcpReceiverSsrcs(rtp_sender_->SSRC()); + } + } + return 0; +} + +bool ModuleRtpRtcpImpl::Sending() const { + return rtcp_sender_.Sending(); +} + +// TODO(nisse): This method shouldn't be called for a receive-only +// stream. Delete rtp_sender_ check as soon as all applications are +// updated. +void ModuleRtpRtcpImpl::SetSendingMediaStatus(const bool sending) { + if (rtp_sender_) { + rtp_sender_->SetSendingMediaStatus(sending); + } else { + RTC_DCHECK(!sending); + } +} + +bool ModuleRtpRtcpImpl::SendingMedia() const { + return rtp_sender_ ? rtp_sender_->SendingMedia() : false; +} + +bool ModuleRtpRtcpImpl::SendOutgoingData( + FrameType frame_type, + int8_t payload_type, + uint32_t time_stamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* rtp_video_header, + uint32_t* transport_frame_id_out) { + rtcp_sender_.SetLastRtpTime(time_stamp, capture_time_ms); + // Make sure an RTCP report isn't queued behind a key frame. + if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) { + rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport); + } + int64_t expected_retransmission_time_ms = rtt_ms(); + if (expected_retransmission_time_ms == 0) { + // No rtt available (|kRtpRtcpRttProcessTimeMs| not yet passed?), so try to + // poll avg_rtt_ms directly from rtcp receiver. + if (rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), nullptr, + &expected_retransmission_time_ms, nullptr, + nullptr) == -1) { + expected_retransmission_time_ms = kDefaultExpectedRetransmissionTimeMs; + } + } + return rtp_sender_->SendOutgoingData( + frame_type, payload_type, time_stamp, capture_time_ms, payload_data, + payload_size, fragmentation, rtp_video_header, transport_frame_id_out, + expected_retransmission_time_ms); +} + +bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission, + const PacedPacketInfo& pacing_info) { + return rtp_sender_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms, + retransmission, pacing_info); +} + +size_t ModuleRtpRtcpImpl::TimeToSendPadding( + size_t bytes, + const PacedPacketInfo& pacing_info) { + return rtp_sender_->TimeToSendPadding(bytes, pacing_info); +} + +size_t ModuleRtpRtcpImpl::MaxRtpPacketSize() const { + return rtp_sender_->MaxRtpPacketSize(); +} + +void ModuleRtpRtcpImpl::SetMaxRtpPacketSize(size_t rtp_packet_size) { + RTC_DCHECK_LE(rtp_packet_size, IP_PACKET_SIZE) + << "rtp packet size too large: " << rtp_packet_size; + RTC_DCHECK_GT(rtp_packet_size, packet_overhead_) + << "rtp packet size too small: " << rtp_packet_size; + + rtcp_sender_.SetMaxRtpPacketSize(rtp_packet_size); + if (rtp_sender_) + rtp_sender_->SetMaxRtpPacketSize(rtp_packet_size); +} + +RtcpMode ModuleRtpRtcpImpl::RTCP() const { + return rtcp_sender_.Status(); +} + +// Configure RTCP status i.e on/off. +void ModuleRtpRtcpImpl::SetRTCPStatus(const RtcpMode method) { + rtcp_sender_.SetRTCPStatus(method); +} + +int32_t ModuleRtpRtcpImpl::SetCNAME(const char* c_name) { + return rtcp_sender_.SetCNAME(c_name); +} + +int32_t ModuleRtpRtcpImpl::AddMixedCNAME(uint32_t ssrc, const char* c_name) { + return rtcp_sender_.AddMixedCNAME(ssrc, c_name); +} + +int32_t ModuleRtpRtcpImpl::RemoveMixedCNAME(const uint32_t ssrc) { + return rtcp_sender_.RemoveMixedCNAME(ssrc); +} + +int32_t ModuleRtpRtcpImpl::RemoteCNAME( + const uint32_t remote_ssrc, + char c_name[RTCP_CNAME_SIZE]) const { + return rtcp_receiver_.CNAME(remote_ssrc, c_name); +} + +int32_t ModuleRtpRtcpImpl::RemoteNTP( + uint32_t* received_ntpsecs, + uint32_t* received_ntpfrac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp) const { + return rtcp_receiver_.NTP(received_ntpsecs, + received_ntpfrac, + rtcp_arrival_time_secs, + rtcp_arrival_time_frac, + rtcp_timestamp) + ? 0 + : -1; +} + +// Get RoundTripTime. +int32_t ModuleRtpRtcpImpl::RTT(const uint32_t remote_ssrc, + int64_t* rtt, + int64_t* avg_rtt, + int64_t* min_rtt, + int64_t* max_rtt) const { + int32_t ret = rtcp_receiver_.RTT(remote_ssrc, rtt, avg_rtt, min_rtt, max_rtt); + if (rtt && *rtt == 0) { + // Try to get RTT from RtcpRttStats class. + *rtt = rtt_ms(); + } + return ret; +} + +// Force a send of an RTCP packet. +// Normal SR and RR are triggered via the process function. +int32_t ModuleRtpRtcpImpl::SendRTCP(RTCPPacketType packet_type) { + return rtcp_sender_.SendRTCP(GetFeedbackState(), packet_type); +} + +// Force a send of an RTCP packet. +// Normal SR and RR are triggered via the process function. +int32_t ModuleRtpRtcpImpl::SendCompoundRTCP( + const std::set<RTCPPacketType>& packet_types) { + return rtcp_sender_.SendCompoundRTCP(GetFeedbackState(), packet_types); +} + +int32_t ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData( + const uint8_t sub_type, + const uint32_t name, + const uint8_t* data, + const uint16_t length) { + return rtcp_sender_.SetApplicationSpecificData(sub_type, name, data, length); +} + +// (XR) VOIP metric. +int32_t ModuleRtpRtcpImpl::SetRTCPVoIPMetrics( + const RTCPVoIPMetric* voip_metric) { + return rtcp_sender_.SetRTCPVoIPMetrics(voip_metric); +} + +void ModuleRtpRtcpImpl::SetRtcpXrRrtrStatus(bool enable) { + rtcp_receiver_.SetRtcpXrRrtrStatus(enable); + rtcp_sender_.SendRtcpXrReceiverReferenceTime(enable); +} + +bool ModuleRtpRtcpImpl::RtcpXrRrtrStatus() const { + return rtcp_sender_.RtcpXrReceiverReferenceTime(); +} + +// TODO(asapersson): Replace this method with the one below. +int32_t ModuleRtpRtcpImpl::DataCountersRTP( + size_t* bytes_sent, + uint32_t* packets_sent) const { + StreamDataCounters rtp_stats; + StreamDataCounters rtx_stats; + rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats); + + if (bytes_sent) { + *bytes_sent = rtp_stats.transmitted.payload_bytes + + rtp_stats.transmitted.padding_bytes + + rtp_stats.transmitted.header_bytes + + rtx_stats.transmitted.payload_bytes + + rtx_stats.transmitted.padding_bytes + + rtx_stats.transmitted.header_bytes; + } + if (packets_sent) { + *packets_sent = rtp_stats.transmitted.packets + + rtx_stats.transmitted.packets; + } + return 0; +} + +void ModuleRtpRtcpImpl::GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const { + rtp_sender_->GetDataCounters(rtp_counters, rtx_counters); +} + +void ModuleRtpRtcpImpl::GetRtpPacketLossStats( + bool outgoing, + uint32_t ssrc, + struct RtpPacketLossStats* loss_stats) const { + if (!loss_stats) return; + const PacketLossStats* stats_source = NULL; + if (outgoing) { + if (SSRC() == ssrc) { + stats_source = &send_loss_stats_; + } + } else { + if (rtcp_receiver_.RemoteSSRC() == ssrc) { + stats_source = &receive_loss_stats_; + } + } + if (stats_source) { + loss_stats->single_packet_loss_count = + stats_source->GetSingleLossCount(); + loss_stats->multiple_packet_loss_event_count = + stats_source->GetMultipleLossEventCount(); + loss_stats->multiple_packet_loss_packet_count = + stats_source->GetMultipleLossPacketCount(); + } +} + +// Received RTCP report. +void ModuleRtpRtcpImpl::RemoteRTCPSenderInfo(uint32_t* packet_count, + uint32_t* octet_count, + NtpTime* ntp_timestamp) const { + return rtcp_receiver_.RemoteRTCPSenderInfo(packet_count, octet_count, + ntp_timestamp); +} + +int32_t ModuleRtpRtcpImpl::RemoteRTCPStat( + std::vector<RTCPReportBlock>* receive_blocks) const { + return rtcp_receiver_.StatisticsReceived(receive_blocks); +} + +// (REMB) Receiver Estimated Max Bitrate. +void ModuleRtpRtcpImpl::SetRemb(uint32_t bitrate_bps, + const std::vector<uint32_t>& ssrcs) { + rtcp_sender_.SetRemb(bitrate_bps, ssrcs); +} + +void ModuleRtpRtcpImpl::UnsetRemb() { + rtcp_sender_.UnsetRemb(); +} + +int32_t ModuleRtpRtcpImpl::RegisterSendRtpHeaderExtension( + const RTPExtensionType type, + const uint8_t id) { + return rtp_sender_->RegisterRtpHeaderExtension(type, id); +} + +int32_t ModuleRtpRtcpImpl::DeregisterSendRtpHeaderExtension( + const RTPExtensionType type) { + return rtp_sender_->DeregisterRtpHeaderExtension(type); +} + +bool ModuleRtpRtcpImpl::HasBweExtensions() const { + return rtp_sender_->IsRtpHeaderExtensionRegistered( + kRtpExtensionTransportSequenceNumber) || + rtp_sender_->IsRtpHeaderExtensionRegistered( + kRtpExtensionAbsoluteSendTime) || + rtp_sender_->IsRtpHeaderExtensionRegistered( + kRtpExtensionTransmissionTimeOffset); +} + +// (TMMBR) Temporary Max Media Bit Rate. +bool ModuleRtpRtcpImpl::TMMBR() const { + return rtcp_sender_.TMMBR(); +} + +void ModuleRtpRtcpImpl::SetTMMBRStatus(const bool enable) { + rtcp_sender_.SetTMMBRStatus(enable); +} + +void ModuleRtpRtcpImpl::SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) { + rtcp_sender_.SetTmmbn(std::move(bounding_set)); +} + +// Returns the currently configured retransmission mode. +int ModuleRtpRtcpImpl::SelectiveRetransmissions() const { + return rtp_sender_->SelectiveRetransmissions(); +} + +// Enable or disable a retransmission mode, which decides which packets will +// be retransmitted if NACKed. +int ModuleRtpRtcpImpl::SetSelectiveRetransmissions(uint8_t settings) { + return rtp_sender_->SetSelectiveRetransmissions(settings); +} + +// Send a Negative acknowledgment packet. +int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list, + const uint16_t size) { + for (int i = 0; i < size; ++i) { + receive_loss_stats_.AddLostPacket(nack_list[i]); + } + uint16_t nack_length = size; + uint16_t start_id = 0; + int64_t now = clock_->TimeInMilliseconds(); + if (TimeToSendFullNackList(now)) { + nack_last_time_sent_full_ = now; + nack_last_time_sent_full_prev_ = now; + } else { + // Only send extended list. + if (nack_last_seq_number_sent_ == nack_list[size - 1]) { + // Last sequence number is the same, do not send list. + return 0; + } + // Send new sequence numbers. + for (int i = 0; i < size; ++i) { + if (nack_last_seq_number_sent_ == nack_list[i]) { + start_id = i + 1; + break; + } + } + nack_length = size - start_id; + } + + // Our RTCP NACK implementation is limited to kRtcpMaxNackFields sequence + // numbers per RTCP packet. + if (nack_length > kRtcpMaxNackFields) { + nack_length = kRtcpMaxNackFields; + } + nack_last_seq_number_sent_ = nack_list[start_id + nack_length - 1]; + + return rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpNack, nack_length, + &nack_list[start_id]); +} + +void ModuleRtpRtcpImpl::SendNack( + const std::vector<uint16_t>& sequence_numbers) { + rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpNack, sequence_numbers.size(), + sequence_numbers.data()); +} + +bool ModuleRtpRtcpImpl::TimeToSendFullNackList(int64_t now) const { + // Use RTT from RtcpRttStats class if provided. + int64_t rtt = rtt_ms(); + if (rtt == 0) { + rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL); + } + + const int64_t kStartUpRttMs = 100; + int64_t wait_time = 5 + ((rtt * 3) >> 1); // 5 + RTT * 1.5. + if (rtt == 0) { + wait_time = kStartUpRttMs; + } + + // Send a full NACK list once within every |wait_time|. + if (rtt_stats_) { + return now - nack_last_time_sent_full_ > wait_time; + } + return now - nack_last_time_sent_full_prev_ > wait_time; +} + +// Store the sent packets, needed to answer to Negative acknowledgment requests. +void ModuleRtpRtcpImpl::SetStorePacketsStatus(const bool enable, + const uint16_t number_to_store) { + rtp_sender_->SetStorePacketsStatus(enable, number_to_store); +} + +bool ModuleRtpRtcpImpl::StorePackets() const { + return rtp_sender_->StorePackets(); +} + +void ModuleRtpRtcpImpl::RegisterRtcpStatisticsCallback( + RtcpStatisticsCallback* callback) { + rtcp_receiver_.RegisterRtcpStatisticsCallback(callback); +} + +RtcpStatisticsCallback* ModuleRtpRtcpImpl::GetRtcpStatisticsCallback() { + return rtcp_receiver_.GetRtcpStatisticsCallback(); +} + +bool ModuleRtpRtcpImpl::SendFeedbackPacket( + const rtcp::TransportFeedback& packet) { + return rtcp_sender_.SendFeedbackPacket(packet); +} + +// Send a TelephoneEvent tone using RFC 2833 (4733). +int32_t ModuleRtpRtcpImpl::SendTelephoneEventOutband( + const uint8_t key, + const uint16_t time_ms, + const uint8_t level) { + return rtp_sender_->SendTelephoneEvent(key, time_ms, level); +} + +int32_t ModuleRtpRtcpImpl::SetAudioLevel( + const uint8_t level_d_bov) { + return rtp_sender_->SetAudioLevel(level_d_bov); +} + +int32_t ModuleRtpRtcpImpl::SetKeyFrameRequestMethod( + const KeyFrameRequestMethod method) { + key_frame_req_method_ = method; + return 0; +} + +int32_t ModuleRtpRtcpImpl::RequestKeyFrame() { + switch (key_frame_req_method_) { + case kKeyFrameReqPliRtcp: + return SendRTCP(kRtcpPli); + case kKeyFrameReqFirRtcp: + return SendRTCP(kRtcpFir); + } + return -1; +} + +void ModuleRtpRtcpImpl::SetUlpfecConfig(int red_payload_type, + int ulpfec_payload_type) { + rtp_sender_->SetUlpfecConfig(red_payload_type, ulpfec_payload_type); +} + +bool ModuleRtpRtcpImpl::SetFecParameters( + const FecProtectionParams& delta_params, + const FecProtectionParams& key_params) { + return rtp_sender_->SetFecParameters(delta_params, key_params); +} + +void ModuleRtpRtcpImpl::SetRemoteSSRC(const uint32_t ssrc) { + // Inform about the incoming SSRC. + rtcp_sender_.SetRemoteSSRC(ssrc); + rtcp_receiver_.SetRemoteSSRC(ssrc); +} + +void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate, + uint32_t* video_rate, + uint32_t* fec_rate, + uint32_t* nack_rate) const { + *total_rate = rtp_sender_->BitrateSent(); + *video_rate = rtp_sender_->VideoBitrateSent(); + *fec_rate = rtp_sender_->FecOverheadRate(); + *nack_rate = rtp_sender_->NackOverheadRate(); +} + +void ModuleRtpRtcpImpl::OnRequestSendReport() { + SendRTCP(kRtcpSr); +} + +bool ModuleRtpRtcpImpl::GetSendReportMetadata(const uint32_t send_report, + uint64_t *time_of_send, + uint32_t *packet_count, + uint64_t *octet_count) { + return rtcp_sender_.GetSendReportMetadata(send_report, + time_of_send, + packet_count, + octet_count); +} + +void ModuleRtpRtcpImpl::OnReceivedNack( + const std::vector<uint16_t>& nack_sequence_numbers) { + if (!rtp_sender_) + return; + + for (uint16_t nack_sequence_number : nack_sequence_numbers) { + send_loss_stats_.AddLostPacket(nack_sequence_number); + } + if (!rtp_sender_->StorePackets() || + nack_sequence_numbers.size() == 0) { + return; + } + // Use RTT from RtcpRttStats class if provided. + int64_t rtt = rtt_ms(); + if (rtt == 0) { + rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL); + } + rtp_sender_->OnReceivedNack(nack_sequence_numbers, rtt); +} + +void ModuleRtpRtcpImpl::OnReceivedRtcpReportBlocks( + const ReportBlockList& report_blocks) { + if (rtp_sender_) + rtp_sender_->OnReceivedRtcpReportBlocks(report_blocks); +} + +bool ModuleRtpRtcpImpl::LastReceivedNTP( + uint32_t* rtcp_arrival_time_secs, // When we got the last report. + uint32_t* rtcp_arrival_time_frac, + uint32_t* remote_sr) const { + // Remote SR: NTP inside the last received (mid 16 bits from sec and frac). + uint32_t ntp_secs = 0; + uint32_t ntp_frac = 0; + + if (!rtcp_receiver_.NTP(&ntp_secs, + &ntp_frac, + rtcp_arrival_time_secs, + rtcp_arrival_time_frac, + NULL)) { + return false; + } + *remote_sr = + ((ntp_secs & 0x0000ffff) << 16) + ((ntp_frac & 0xffff0000) >> 16); + return true; +} + +// Called from RTCPsender. +std::vector<rtcp::TmmbItem> ModuleRtpRtcpImpl::BoundingSet(bool* tmmbr_owner) { + return rtcp_receiver_.BoundingSet(tmmbr_owner); +} + +int64_t ModuleRtpRtcpImpl::RtcpReportInterval() { + if (audio_) + return RTCP_INTERVAL_AUDIO_MS; + else + return RTCP_INTERVAL_VIDEO_MS; +} + +void ModuleRtpRtcpImpl::SetRtcpReceiverSsrcs(uint32_t main_ssrc) { + std::set<uint32_t> ssrcs; + ssrcs.insert(main_ssrc); + if (RtxSendStatus() != kRtxOff) + ssrcs.insert(rtp_sender_->RtxSsrc()); + rtc::Optional<uint32_t> flexfec_ssrc = FlexfecSsrc(); + if (flexfec_ssrc) + ssrcs.insert(*flexfec_ssrc); + rtcp_receiver_.SetSsrcs(main_ssrc, ssrcs); +} + +void ModuleRtpRtcpImpl::set_rtt_ms(int64_t rtt_ms) { + rtc::CritScope cs(&critical_section_rtt_); + rtt_ms_ = rtt_ms; +} + +int64_t ModuleRtpRtcpImpl::rtt_ms() const { + rtc::CritScope cs(&critical_section_rtt_); + return rtt_ms_; +} + +void ModuleRtpRtcpImpl::RegisterSendChannelRtpStatisticsCallback( + StreamDataCountersCallback* callback) { + rtp_sender_->RegisterRtpStatisticsCallback(callback); +} + +StreamDataCountersCallback* + ModuleRtpRtcpImpl::GetSendChannelRtpStatisticsCallback() const { + return rtp_sender_->GetRtpStatisticsCallback(); +} + +void ModuleRtpRtcpImpl::SetVideoBitrateAllocation( + const BitrateAllocation& bitrate) { + rtcp_sender_.SetVideoBitrateAllocation(bitrate); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h new file mode 100644 index 0000000000..f4dd73b56a --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -0,0 +1,369 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL_H_ + +#include <memory> +#include <set> +#include <utility> +#include <vector> + +#include "api/optional.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/packet_loss_stats.h" +#include "modules/rtp_rtcp/source/rtcp_receiver.h" +#include "modules/rtp_rtcp/source/rtcp_sender.h" +#include "modules/rtp_rtcp/source/rtp_sender.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/gtest_prod_util.h" + +namespace webrtc { + +class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp { + public: + explicit ModuleRtpRtcpImpl(const RtpRtcp::Configuration& configuration); + + // Returns the number of milliseconds until the module want a worker thread to + // call Process. + int64_t TimeUntilNextProcess() override; + + // Process any pending tasks such as timeouts. + void Process() override; + + // Receiver part. + + // Called when we receive an RTCP packet. + void IncomingRtcpPacket(const uint8_t* incoming_packet, + size_t incoming_packet_length) override; + + void SetRemoteSSRC(uint32_t ssrc) override; + + // Sender part. + + int32_t RegisterSendPayload(const CodecInst& voice_codec) override; + + int32_t RegisterSendPayload(const VideoCodec& video_codec) override; + + void RegisterVideoSendPayload(int payload_type, + const char* payload_name) override; + + int32_t DeRegisterSendPayload(int8_t payload_type) override; + + // Register RTP header extension. + int32_t RegisterSendRtpHeaderExtension(RTPExtensionType type, + uint8_t id) override; + + int32_t DeregisterSendRtpHeaderExtension(RTPExtensionType type) override; + + bool HasBweExtensions() const override; + + // Get start timestamp. + uint32_t StartTimestamp() const override; + + // Configure start timestamp, default is a random number. + void SetStartTimestamp(uint32_t timestamp) override; + + uint16_t SequenceNumber() const override; + + // Set SequenceNumber, default is a random number. + void SetSequenceNumber(uint16_t seq) override; + + void SetRtpState(const RtpState& rtp_state) override; + void SetRtxState(const RtpState& rtp_state) override; + RtpState GetRtpState() const override; + RtpState GetRtxState() const override; + + uint32_t SSRC() const override; + + // Configure SSRC, default is a random number. + void SetSSRC(uint32_t ssrc) override; + + void SetCsrcs(const std::vector<uint32_t>& csrcs) override; + + int32_t SetRID(const char *rid) override; + int32_t SetMID(const char *mid) override; + + RTCPSender::FeedbackState GetFeedbackState(); + + void SetRtxSendStatus(int mode) override; + int RtxSendStatus() const override; + + void SetRtxSsrc(uint32_t ssrc) override; + + void SetRtxSendPayloadType(int payload_type, + int associated_payload_type) override; + + rtc::Optional<uint32_t> FlexfecSsrc() const override; + + // Sends kRtcpByeCode when going from true to false. + int32_t SetSendingStatus(bool sending) override; + + bool Sending() const override; + + // Drops or relays media packets. + void SetSendingMediaStatus(bool sending) override; + + bool SendingMedia() const override; + + // Used by the codec module to deliver a video or audio frame for + // packetization. + bool SendOutgoingData(FrameType frame_type, + int8_t payload_type, + uint32_t time_stamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* rtp_video_header, + uint32_t* transport_frame_id_out) override; + + bool TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission, + const PacedPacketInfo& pacing_info) override; + + // Returns the number of padding bytes actually sent, which can be more or + // less than |bytes|. + size_t TimeToSendPadding(size_t bytes, + const PacedPacketInfo& pacing_info) override; + + // RTCP part. + + // Get RTCP status. + RtcpMode RTCP() const override; + + // Configure RTCP status i.e on/off. + void SetRTCPStatus(RtcpMode method) override; + + // Set RTCP CName. + int32_t SetCNAME(const char* c_name) override; + + // Get remote CName. + int32_t RemoteCNAME(uint32_t remote_ssrc, + char c_name[RTCP_CNAME_SIZE]) const override; + + // Get remote NTP. + int32_t RemoteNTP(uint32_t* received_ntp_secs, + uint32_t* received_ntp_frac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp) const override; + + int32_t AddMixedCNAME(uint32_t ssrc, const char* c_name) override; + + int32_t RemoveMixedCNAME(uint32_t ssrc) override; + + // Get RoundTripTime. + int32_t RTT(uint32_t remote_ssrc, + int64_t* rtt, + int64_t* avg_rtt, + int64_t* min_rtt, + int64_t* max_rtt) const override; + + // Force a send of an RTCP packet. + // Normal SR and RR are triggered via the process function. + int32_t SendRTCP(RTCPPacketType rtcpPacketType) override; + + int32_t SendCompoundRTCP( + const std::set<RTCPPacketType>& rtcpPacketTypes) override; + + // Statistics of the amount of data sent and received. + int32_t DataCountersRTP(size_t* bytes_sent, + uint32_t* packets_sent) const override; + + void GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const override; + + void GetRtpPacketLossStats( + bool outgoing, + uint32_t ssrc, + struct RtpPacketLossStats* loss_stats) const override; + + void RemoteRTCPSenderInfo(uint32_t* packet_count, + uint32_t* octet_count, + NtpTime* ntp_timestamp) const override; + + // Get received RTCP report, report block. + int32_t RemoteRTCPStat( + std::vector<RTCPReportBlock>* receive_blocks) const override; + + // (REMB) Receiver Estimated Max Bitrate. + void SetRemb(uint32_t bitrate_bps, + const std::vector<uint32_t>& ssrcs) override; + void UnsetRemb() override; + + // (TMMBR) Temporary Max Media Bit Rate. + bool TMMBR() const override; + + void SetTMMBRStatus(bool enable) override; + + void SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) override; + + size_t MaxRtpPacketSize() const override; + + void SetMaxRtpPacketSize(size_t max_packet_size) override; + + // (NACK) Negative acknowledgment part. + + int SelectiveRetransmissions() const override; + + int SetSelectiveRetransmissions(uint8_t settings) override; + + // Send a Negative acknowledgment packet. + // TODO(philipel): Deprecate SendNACK and use SendNack instead. + int32_t SendNACK(const uint16_t* nack_list, uint16_t size) override; + + void SendNack(const std::vector<uint16_t>& sequence_numbers) override; + + // Store the sent packets, needed to answer to a negative acknowledgment + // requests. + void SetStorePacketsStatus(bool enable, uint16_t number_to_store) override; + + bool StorePackets() const override; + + bool GetSendReportMetadata(const uint32_t send_report, + uint64_t *time_of_send, + uint32_t *packet_count, + uint64_t *octet_count) override; + + // Called on receipt of RTCP report block from remote side. + void RegisterRtcpStatisticsCallback( + RtcpStatisticsCallback* callback) override; + RtcpStatisticsCallback* GetRtcpStatisticsCallback() override; + + bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override; + // (APP) Application specific data. + int32_t SetRTCPApplicationSpecificData(uint8_t sub_type, + uint32_t name, + const uint8_t* data, + uint16_t length) override; + + // (XR) VOIP metric. + int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) override; + + // (XR) Receiver reference time report. + void SetRtcpXrRrtrStatus(bool enable) override; + + bool RtcpXrRrtrStatus() const override; + + // Audio part. + + // Send a TelephoneEvent tone using RFC 2833 (4733). + int32_t SendTelephoneEventOutband(uint8_t key, + uint16_t time_ms, + uint8_t level) override; + + // Store the audio level in d_bov for header-extension-for-audio-level- + // indication. + int32_t SetAudioLevel(uint8_t level_d_bov) override; + + // Video part. + + // Set method for requesting a new key frame. + int32_t SetKeyFrameRequestMethod(KeyFrameRequestMethod method) override; + + // Send a request for a keyframe. + int32_t RequestKeyFrame() override; + + void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) override; + + bool SetFecParameters(const FecProtectionParams& delta_params, + const FecProtectionParams& key_params) override; + + bool LastReceivedNTP(uint32_t* NTPsecs, + uint32_t* NTPfrac, + uint32_t* remote_sr) const; + + std::vector<rtcp::TmmbItem> BoundingSet(bool* tmmbr_owner); + + void BitrateSent(uint32_t* total_rate, + uint32_t* video_rate, + uint32_t* fec_rate, + uint32_t* nackRate) const override; + + void RegisterSendChannelRtpStatisticsCallback( + StreamDataCountersCallback* callback) override; + StreamDataCountersCallback* GetSendChannelRtpStatisticsCallback() + const override; + + void OnReceivedNack( + const std::vector<uint16_t>& nack_sequence_numbers) override; + void OnReceivedRtcpReportBlocks( + const ReportBlockList& report_blocks) override; + void OnRequestSendReport() override; + + void SetVideoBitrateAllocation(const BitrateAllocation& bitrate) override; + + protected: + bool UpdateRTCPReceiveInformationTimers(); + + RTPSender* rtp_sender() { return rtp_sender_.get(); } + const RTPSender* rtp_sender() const { return rtp_sender_.get(); } + + RTCPSender* rtcp_sender() { return &rtcp_sender_; } + const RTCPSender* rtcp_sender() const { return &rtcp_sender_; } + + RTCPReceiver* rtcp_receiver() { return &rtcp_receiver_; } + const RTCPReceiver* rtcp_receiver() const { return &rtcp_receiver_; } + + const Clock* clock() const { return clock_; } + + private: + FRIEND_TEST_ALL_PREFIXES(RtpRtcpImplTest, Rtt); + FRIEND_TEST_ALL_PREFIXES(RtpRtcpImplTest, RttForReceiverOnly); + int64_t RtcpReportInterval(); + void SetRtcpReceiverSsrcs(uint32_t main_ssrc); + + void set_rtt_ms(int64_t rtt_ms); + int64_t rtt_ms() const; + + bool TimeToSendFullNackList(int64_t now) const; + + std::unique_ptr<RTPSender> rtp_sender_; + RTCPSender rtcp_sender_; + RTCPReceiver rtcp_receiver_; + + const Clock* const clock_; + + const bool audio_; + + const RtpKeepAliveConfig keepalive_config_; + int64_t last_bitrate_process_time_; + int64_t last_rtt_process_time_; + int64_t next_process_time_; + int64_t next_keepalive_time_; + uint16_t packet_overhead_; + + // Send side + int64_t nack_last_time_sent_full_; + uint32_t nack_last_time_sent_full_prev_; + uint16_t nack_last_seq_number_sent_; + + KeyFrameRequestMethod key_frame_req_method_; + + RemoteBitrateEstimator* remote_bitrate_; + + RtcpRttStats* rtt_stats_; + + PacketLossStats send_loss_stats_; + PacketLossStats receive_loss_stats_; + + // The processed RTT from RtcpRttStats. + rtc::CriticalSection critical_section_rtt_; + int64_t rtt_ms_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc new file mode 100644 index 0000000000..ad3ec0bbed --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc @@ -0,0 +1,646 @@ +/* + * 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 <map> +#include <memory> +#include <set> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h" +#include "rtc_base/rate_limiter.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" + +using ::testing::_; +using ::testing::ElementsAre; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::SaveArg; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345; +const uint32_t kReceiverSsrc = 0x23456; +const int64_t kOneWayNetworkDelayMs = 100; +const uint8_t kBaseLayerTid = 0; +const uint8_t kHigherLayerTid = 1; +const uint16_t kSequenceNumber = 100; +const int64_t kMaxRttMs = 1000; + +class RtcpRttStatsTestImpl : public RtcpRttStats { + public: + RtcpRttStatsTestImpl() : rtt_ms_(0) {} + virtual ~RtcpRttStatsTestImpl() {} + + void OnRttUpdate(int64_t rtt_ms) override { rtt_ms_ = rtt_ms; } + int64_t LastProcessedRtt() const override { return rtt_ms_; } + int64_t rtt_ms_; +}; + +class SendTransport : public Transport, + public RtpData { + public: + SendTransport() + : receiver_(nullptr), + clock_(nullptr), + delay_ms_(0), + rtp_packets_sent_(0), + keepalive_payload_type_(0), + num_keepalive_sent_(0) {} + + void SetRtpRtcpModule(ModuleRtpRtcpImpl* receiver) { + receiver_ = receiver; + } + void SimulateNetworkDelay(int64_t delay_ms, SimulatedClock* clock) { + clock_ = clock; + delay_ms_ = delay_ms; + } + bool SendRtp(const uint8_t* data, + size_t len, + const PacketOptions& options) override { + RTPHeader header; + std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create()); + EXPECT_TRUE(parser->Parse(static_cast<const uint8_t*>(data), len, &header)); + ++rtp_packets_sent_; + if (header.payloadType == keepalive_payload_type_) + ++num_keepalive_sent_; + last_rtp_header_ = header; + return true; + } + bool SendRtcp(const uint8_t* data, size_t len) override { + test::RtcpPacketParser parser; + parser.Parse(data, len); + last_nack_list_ = parser.nack()->packet_ids(); + + if (clock_) { + clock_->AdvanceTimeMilliseconds(delay_ms_); + } + EXPECT_TRUE(receiver_); + receiver_->IncomingRtcpPacket(data, len); + return true; + } + int32_t OnReceivedPayloadData(const uint8_t* payload_data, + size_t payload_size, + const WebRtcRTPHeader* rtp_header) override { + return 0; + } + void SetKeepalivePayloadType(uint8_t payload_type) { + keepalive_payload_type_ = payload_type; + } + size_t NumKeepaliveSent() { return num_keepalive_sent_; } + ModuleRtpRtcpImpl* receiver_; + SimulatedClock* clock_; + int64_t delay_ms_; + int rtp_packets_sent_; + RTPHeader last_rtp_header_; + std::vector<uint16_t> last_nack_list_; + uint8_t keepalive_payload_type_; + size_t num_keepalive_sent_; +}; + +class RtpRtcpModule : public RtcpPacketTypeCounterObserver { + public: + explicit RtpRtcpModule(SimulatedClock* clock) + : receive_statistics_(ReceiveStatistics::Create(clock)), + remote_ssrc_(0), + retransmission_rate_limiter_(clock, kMaxRttMs), + clock_(clock) { + CreateModuleImpl(); + transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock); + } + + RtcpPacketTypeCounter packets_sent_; + RtcpPacketTypeCounter packets_received_; + std::unique_ptr<ReceiveStatistics> receive_statistics_; + SendTransport transport_; + RtcpRttStatsTestImpl rtt_stats_; + std::unique_ptr<ModuleRtpRtcpImpl> impl_; + uint32_t remote_ssrc_; + RateLimiter retransmission_rate_limiter_; + RtpKeepAliveConfig keepalive_config_; + + void SetRemoteSsrc(uint32_t ssrc) { + remote_ssrc_ = ssrc; + impl_->SetRemoteSSRC(ssrc); + } + + void RtcpPacketTypesCounterUpdated( + uint32_t ssrc, + const RtcpPacketTypeCounter& packet_counter) override { + counter_map_[ssrc] = packet_counter; + } + + RtcpPacketTypeCounter RtcpSent() { + // RTCP counters for remote SSRC. + return counter_map_[remote_ssrc_]; + } + + RtcpPacketTypeCounter RtcpReceived() { + // Received RTCP stats for (own) local SSRC. + return counter_map_[impl_->SSRC()]; + } + int RtpSent() { + return transport_.rtp_packets_sent_; + } + uint16_t LastRtpSequenceNumber() { + return transport_.last_rtp_header_.sequenceNumber; + } + std::vector<uint16_t> LastNackListSent() { + return transport_.last_nack_list_; + } + void SetKeepaliveConfigAndReset(const RtpKeepAliveConfig& config) { + keepalive_config_ = config; + // Need to create a new module impl, since it's configured at creation. + CreateModuleImpl(); + transport_.SetKeepalivePayloadType(config.payload_type); + } + + private: + void CreateModuleImpl() { + RtpRtcp::Configuration config; + config.audio = false; + config.clock = clock_; + config.outgoing_transport = &transport_; + config.receive_statistics = receive_statistics_.get(); + config.rtcp_packet_type_counter_observer = this; + config.rtt_stats = &rtt_stats_; + config.retransmission_rate_limiter = &retransmission_rate_limiter_; + config.keepalive_config = keepalive_config_; + + impl_.reset(new ModuleRtpRtcpImpl(config)); + impl_->SetRTCPStatus(RtcpMode::kCompound); + } + + SimulatedClock* const clock_; + std::map<uint32_t, RtcpPacketTypeCounter> counter_map_; +}; +} // namespace + +class RtpRtcpImplTest : public ::testing::Test { + protected: + RtpRtcpImplTest() + : clock_(133590000000000), sender_(&clock_), receiver_(&clock_) {} + + void SetUp() override { + // Send module. + sender_.impl_->SetSSRC(kSenderSsrc); + EXPECT_EQ(0, sender_.impl_->SetSendingStatus(true)); + sender_.impl_->SetSendingMediaStatus(true); + sender_.SetRemoteSsrc(kReceiverSsrc); + sender_.impl_->SetSequenceNumber(kSequenceNumber); + sender_.impl_->SetStorePacketsStatus(true, 100); + + memset(&codec_, 0, sizeof(VideoCodec)); + codec_.plType = 100; + strncpy(codec_.plName, "VP8", 3); + codec_.width = 320; + codec_.height = 180; + EXPECT_EQ(0, sender_.impl_->RegisterSendPayload(codec_)); + + // Receive module. + EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false)); + receiver_.impl_->SetSendingMediaStatus(false); + receiver_.impl_->SetSSRC(kReceiverSsrc); + receiver_.SetRemoteSsrc(kSenderSsrc); + // Transport settings. + sender_.transport_.SetRtpRtcpModule(receiver_.impl_.get()); + receiver_.transport_.SetRtpRtcpModule(sender_.impl_.get()); + } + + SimulatedClock clock_; + RtpRtcpModule sender_; + RtpRtcpModule receiver_; + VideoCodec codec_; + + void SendFrame(const RtpRtcpModule* module, uint8_t tid) { + RTPVideoHeaderVP8 vp8_header = {}; + vp8_header.temporalIdx = tid; + RTPVideoHeader rtp_video_header; + rtp_video_header.width = codec_.width; + rtp_video_header.height = codec_.height; + rtp_video_header.rotation = kVideoRotation_0; + rtp_video_header.content_type = VideoContentType::UNSPECIFIED; + rtp_video_header.playout_delay = {-1, -1}; + rtp_video_header.is_first_packet_in_frame = true; + rtp_video_header.simulcastIdx = 0; + rtp_video_header.codec = kRtpVideoVp8; + rtp_video_header.codecHeader = {vp8_header}; + rtp_video_header.video_timing = {0u, 0u, 0u, 0u, 0u, 0u, false}; + + const uint8_t payload[100] = {0}; + EXPECT_EQ(true, module->impl_->SendOutgoingData( + kVideoFrameKey, codec_.plType, 0, 0, payload, + sizeof(payload), nullptr, &rtp_video_header, nullptr)); + } + + void IncomingRtcpNack(const RtpRtcpModule* module, uint16_t sequence_number) { + bool sender = module->impl_->SSRC() == kSenderSsrc; + rtcp::Nack nack; + uint16_t list[1]; + list[0] = sequence_number; + const uint16_t kListLength = sizeof(list) / sizeof(list[0]); + nack.SetSenderSsrc(sender ? kReceiverSsrc : kSenderSsrc); + nack.SetMediaSsrc(sender ? kSenderSsrc : kReceiverSsrc); + nack.SetPacketIds(list, kListLength); + rtc::Buffer packet = nack.Build(); + module->impl_->IncomingRtcpPacket(packet.data(), packet.size()); + } +}; + +TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_BaseLayer) { + sender_.impl_->SetSelectiveRetransmissions(kRetransmitBaseLayer); + EXPECT_EQ(kRetransmitBaseLayer, sender_.impl_->SelectiveRetransmissions()); + + // Send frames. + EXPECT_EQ(0, sender_.RtpSent()); + SendFrame(&sender_, kBaseLayerTid); // kSequenceNumber + SendFrame(&sender_, kHigherLayerTid); // kSequenceNumber + 1 + SendFrame(&sender_, kNoTemporalIdx); // kSequenceNumber + 2 + EXPECT_EQ(3, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber()); + + // Min required delay until retransmit = 5 + RTT ms (RTT = 0). + clock_.AdvanceTimeMilliseconds(5); + + // Frame with kBaseLayerTid re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber); + EXPECT_EQ(4, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber()); + // Frame with kHigherLayerTid not re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber + 1); + EXPECT_EQ(4, sender_.RtpSent()); + // Frame with kNoTemporalIdx re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber + 2); + EXPECT_EQ(5, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber()); +} + +TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_HigherLayers) { + const uint8_t kSetting = kRetransmitBaseLayer + kRetransmitHigherLayers; + sender_.impl_->SetSelectiveRetransmissions(kSetting); + EXPECT_EQ(kSetting, sender_.impl_->SelectiveRetransmissions()); + + // Send frames. + EXPECT_EQ(0, sender_.RtpSent()); + SendFrame(&sender_, kBaseLayerTid); // kSequenceNumber + SendFrame(&sender_, kHigherLayerTid); // kSequenceNumber + 1 + SendFrame(&sender_, kNoTemporalIdx); // kSequenceNumber + 2 + EXPECT_EQ(3, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber()); + + // Min required delay until retransmit = 5 + RTT ms (RTT = 0). + clock_.AdvanceTimeMilliseconds(5); + + // Frame with kBaseLayerTid re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber); + EXPECT_EQ(4, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber()); + // Frame with kHigherLayerTid re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber + 1); + EXPECT_EQ(5, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 1, sender_.LastRtpSequenceNumber()); + // Frame with kNoTemporalIdx re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber + 2); + EXPECT_EQ(6, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber()); +} + +TEST_F(RtpRtcpImplTest, Rtt) { + RTPHeader header; + header.timestamp = 1; + header.sequenceNumber = 123; + header.ssrc = kSenderSsrc; + header.headerLength = 12; + receiver_.receive_statistics_->IncomingPacket(header, 100, false); + + // Send Frame before sending an SR. + SendFrame(&sender_, kBaseLayerTid); + // Sender module should send an SR. + EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport)); + + // Receiver module should send a RR with a response to the last received SR. + clock_.AdvanceTimeMilliseconds(1000); + EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport)); + + // Verify RTT. + int64_t rtt; + int64_t avg_rtt; + int64_t min_rtt; + int64_t max_rtt; + EXPECT_EQ(0, + sender_.impl_->RTT(kReceiverSsrc, &rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, rtt, 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, avg_rtt, 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, min_rtt, 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, max_rtt, 1); + + // No RTT from other ssrc. + EXPECT_EQ(-1, + sender_.impl_->RTT(kReceiverSsrc+1, &rtt, &avg_rtt, &min_rtt, &max_rtt)); + + // Verify RTT from rtt_stats config. + EXPECT_EQ(0, sender_.rtt_stats_.LastProcessedRtt()); + EXPECT_EQ(0, sender_.impl_->rtt_ms()); + sender_.impl_->Process(); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, sender_.rtt_stats_.LastProcessedRtt(), + 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, sender_.impl_->rtt_ms(), 1); +} + +TEST_F(RtpRtcpImplTest, SetRtcpXrRrtrStatus) { + EXPECT_FALSE(receiver_.impl_->RtcpXrRrtrStatus()); + receiver_.impl_->SetRtcpXrRrtrStatus(true); + EXPECT_TRUE(receiver_.impl_->RtcpXrRrtrStatus()); +} + +TEST_F(RtpRtcpImplTest, RttForReceiverOnly) { + receiver_.impl_->SetRtcpXrRrtrStatus(true); + + // Receiver module should send a Receiver time reference report (RTRR). + EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport)); + + // Sender module should send a response to the last received RTRR (DLRR). + clock_.AdvanceTimeMilliseconds(1000); + // Send Frame before sending a SR. + SendFrame(&sender_, kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport)); + + // Verify RTT. + EXPECT_EQ(0, receiver_.rtt_stats_.LastProcessedRtt()); + EXPECT_EQ(0, receiver_.impl_->rtt_ms()); + receiver_.impl_->Process(); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, + receiver_.rtt_stats_.LastProcessedRtt(), 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms(), 1); +} + +TEST_F(RtpRtcpImplTest, NoSrBeforeMedia) { + // Ignore fake transport delays in this test. + sender_.transport_.SimulateNetworkDelay(0, &clock_); + receiver_.transport_.SimulateNetworkDelay(0, &clock_); + + sender_.impl_->Process(); + EXPECT_EQ(-1, sender_.RtcpSent().first_packet_time_ms); + + // Verify no SR is sent before media has been sent, RR should still be sent + // from the receiving module though. + clock_.AdvanceTimeMilliseconds(2000); + int64_t current_time = clock_.TimeInMilliseconds(); + sender_.impl_->Process(); + receiver_.impl_->Process(); + EXPECT_EQ(-1, sender_.RtcpSent().first_packet_time_ms); + EXPECT_EQ(receiver_.RtcpSent().first_packet_time_ms, current_time); + + SendFrame(&sender_, kBaseLayerTid); + EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, current_time); +} + +TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_Nack) { + EXPECT_EQ(-1, receiver_.RtcpSent().first_packet_time_ms); + EXPECT_EQ(-1, sender_.RtcpReceived().first_packet_time_ms); + EXPECT_EQ(0U, sender_.RtcpReceived().nack_packets); + EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets); + + // Receive module sends a NACK. + const uint16_t kNackLength = 1; + uint16_t nack_list[kNackLength] = {123}; + EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets); + EXPECT_GT(receiver_.RtcpSent().first_packet_time_ms, -1); + + // Send module receives the NACK. + EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets); + EXPECT_GT(sender_.RtcpReceived().first_packet_time_ms, -1); +} + +TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) { + EXPECT_EQ(0U, sender_.RtcpReceived().fir_packets); + EXPECT_EQ(0U, receiver_.RtcpSent().fir_packets); + // Receive module sends a FIR. + EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir)); + EXPECT_EQ(1U, receiver_.RtcpSent().fir_packets); + // Send module receives the FIR. + EXPECT_EQ(1U, sender_.RtcpReceived().fir_packets); + + // Receive module sends a FIR and PLI. + std::set<RTCPPacketType> packet_types; + packet_types.insert(kRtcpFir); + packet_types.insert(kRtcpPli); + EXPECT_EQ(0, receiver_.impl_->SendCompoundRTCP(packet_types)); + EXPECT_EQ(2U, receiver_.RtcpSent().fir_packets); + EXPECT_EQ(1U, receiver_.RtcpSent().pli_packets); + // Send module receives the FIR and PLI. + EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets); + EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets); +} + +TEST_F(RtpRtcpImplTest, AddStreamDataCounters) { + StreamDataCounters rtp; + const int64_t kStartTimeMs = 1; + rtp.first_packet_time_ms = kStartTimeMs; + rtp.transmitted.packets = 1; + rtp.transmitted.payload_bytes = 1; + rtp.transmitted.header_bytes = 2; + rtp.transmitted.padding_bytes = 3; + EXPECT_EQ(rtp.transmitted.TotalBytes(), rtp.transmitted.payload_bytes + + rtp.transmitted.header_bytes + + rtp.transmitted.padding_bytes); + + StreamDataCounters rtp2; + rtp2.first_packet_time_ms = -1; + rtp2.transmitted.packets = 10; + rtp2.transmitted.payload_bytes = 10; + rtp2.retransmitted.header_bytes = 4; + rtp2.retransmitted.payload_bytes = 5; + rtp2.retransmitted.padding_bytes = 6; + rtp2.retransmitted.packets = 7; + rtp2.fec.packets = 8; + + StreamDataCounters sum = rtp; + sum.Add(rtp2); + EXPECT_EQ(kStartTimeMs, sum.first_packet_time_ms); + EXPECT_EQ(11U, sum.transmitted.packets); + EXPECT_EQ(11U, sum.transmitted.payload_bytes); + EXPECT_EQ(2U, sum.transmitted.header_bytes); + EXPECT_EQ(3U, sum.transmitted.padding_bytes); + EXPECT_EQ(4U, sum.retransmitted.header_bytes); + EXPECT_EQ(5U, sum.retransmitted.payload_bytes); + EXPECT_EQ(6U, sum.retransmitted.padding_bytes); + EXPECT_EQ(7U, sum.retransmitted.packets); + EXPECT_EQ(8U, sum.fec.packets); + EXPECT_EQ(sum.transmitted.TotalBytes(), + rtp.transmitted.TotalBytes() + rtp2.transmitted.TotalBytes()); + + StreamDataCounters rtp3; + rtp3.first_packet_time_ms = kStartTimeMs + 10; + sum.Add(rtp3); + EXPECT_EQ(kStartTimeMs, sum.first_packet_time_ms); // Holds oldest time. +} + +TEST_F(RtpRtcpImplTest, SendsInitialNackList) { + // Send module sends a NACK. + const uint16_t kNackLength = 1; + uint16_t nack_list[kNackLength] = {123}; + EXPECT_EQ(0U, sender_.RtcpSent().nack_packets); + // Send Frame before sending a compound RTCP that starts with SR. + SendFrame(&sender_, kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123)); +} + +TEST_F(RtpRtcpImplTest, SendsExtendedNackList) { + // Send module sends a NACK. + const uint16_t kNackLength = 1; + uint16_t nack_list[kNackLength] = {123}; + EXPECT_EQ(0U, sender_.RtcpSent().nack_packets); + // Send Frame before sending a compound RTCP that starts with SR. + SendFrame(&sender_, kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123)); + + // Same list not re-send. + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123)); + + // Only extended list sent. + const uint16_t kNackExtLength = 2; + uint16_t nack_list_ext[kNackExtLength] = {123, 124}; + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list_ext, kNackExtLength)); + EXPECT_EQ(2U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(124)); +} + +TEST_F(RtpRtcpImplTest, ReSendsNackListAfterRttMs) { + sender_.transport_.SimulateNetworkDelay(0, &clock_); + // Send module sends a NACK. + const uint16_t kNackLength = 2; + uint16_t nack_list[kNackLength] = {123, 125}; + EXPECT_EQ(0U, sender_.RtcpSent().nack_packets); + // Send Frame before sending a compound RTCP that starts with SR. + SendFrame(&sender_, kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123, 125)); + + // Same list not re-send, rtt interval has not passed. + const int kStartupRttMs = 100; + clock_.AdvanceTimeMilliseconds(kStartupRttMs); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + + // Rtt interval passed, full list sent. + clock_.AdvanceTimeMilliseconds(1); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(2U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123, 125)); +} + +TEST_F(RtpRtcpImplTest, UniqueNackRequests) { + receiver_.transport_.SimulateNetworkDelay(0, &clock_); + EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets); + EXPECT_EQ(0U, receiver_.RtcpSent().nack_requests); + EXPECT_EQ(0U, receiver_.RtcpSent().unique_nack_requests); + EXPECT_EQ(0, receiver_.RtcpSent().UniqueNackRequestsInPercent()); + + // Receive module sends NACK request. + const uint16_t kNackLength = 4; + uint16_t nack_list[kNackLength] = {10, 11, 13, 18}; + EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets); + EXPECT_EQ(4U, receiver_.RtcpSent().nack_requests); + EXPECT_EQ(4U, receiver_.RtcpSent().unique_nack_requests); + EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(10, 11, 13, 18)); + + // Send module receives the request. + EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets); + EXPECT_EQ(4U, sender_.RtcpReceived().nack_requests); + EXPECT_EQ(4U, sender_.RtcpReceived().unique_nack_requests); + EXPECT_EQ(100, sender_.RtcpReceived().UniqueNackRequestsInPercent()); + + // Receive module sends new request with duplicated packets. + const int kStartupRttMs = 100; + clock_.AdvanceTimeMilliseconds(kStartupRttMs + 1); + const uint16_t kNackLength2 = 4; + uint16_t nack_list2[kNackLength2] = {11, 18, 20, 21}; + EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list2, kNackLength2)); + EXPECT_EQ(2U, receiver_.RtcpSent().nack_packets); + EXPECT_EQ(8U, receiver_.RtcpSent().nack_requests); + EXPECT_EQ(6U, receiver_.RtcpSent().unique_nack_requests); + EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(11, 18, 20, 21)); + + // Send module receives the request. + EXPECT_EQ(2U, sender_.RtcpReceived().nack_packets); + EXPECT_EQ(8U, sender_.RtcpReceived().nack_requests); + EXPECT_EQ(6U, sender_.RtcpReceived().unique_nack_requests); + EXPECT_EQ(75, sender_.RtcpReceived().UniqueNackRequestsInPercent()); +} + +TEST_F(RtpRtcpImplTest, SendsKeepaliveAfterTimout) { + const int kTimeoutMs = 1500; + + RtpKeepAliveConfig config; + config.timeout_interval_ms = kTimeoutMs; + + // Recreate sender impl with new configuration, and redo setup. + sender_.SetKeepaliveConfigAndReset(config); + SetUp(); + + // Initial process call. + sender_.impl_->Process(); + EXPECT_EQ(0U, sender_.transport_.NumKeepaliveSent()); + + // After one time, a single keep-alive packet should be sent. + clock_.AdvanceTimeMilliseconds(kTimeoutMs); + sender_.impl_->Process(); + EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent()); + + // Process for the same timestamp again, no new packet should be sent. + sender_.impl_->Process(); + EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent()); + + // Move ahead to the last ms before a keep-alive is expected, no action. + clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1); + sender_.impl_->Process(); + EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent()); + + // Move the final ms, timeout relative last KA. Should create new keep-alive. + clock_.AdvanceTimeMilliseconds(1); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Move ahead to the last ms before Christmas. + clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Send actual payload data, no keep-alive expected. + SendFrame(&sender_, 0); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Move ahead as far as possible again, timeout now relative payload. No KA. + clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Timeout relative payload, send new keep-alive. + clock_.AdvanceTimeMilliseconds(1); + sender_.impl_->Process(); + EXPECT_EQ(3U, sender_.transport_.NumKeepaliveSent()); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.cc new file mode 100644 index 0000000000..08ddc810e7 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -0,0 +1,1412 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_sender.h" + +#include <algorithm> +#include <utility> + +#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h" +#include "logging/rtc_event_log/rtc_event_log.h" +#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" +#include "modules/rtp_rtcp/include/rtp_cvo.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/playout_delay_oracle.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "modules/rtp_rtcp/source/rtp_sender_audio.h" +#include "modules/rtp_rtcp/source/rtp_sender_video.h" +#include "modules/rtp_rtcp/source/time_util.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_minmax.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/rate_limiter.h" +#include "rtc_base/timeutils.h" +#include "rtc_base/trace_event.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { + +namespace { +// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP. +constexpr size_t kMaxPaddingLength = 224; +constexpr size_t kMinAudioPaddingLength = 50; +constexpr int kSendSideDelayWindowMs = 1000; +constexpr size_t kRtpHeaderLength = 12; +constexpr uint16_t kMaxInitRtpSeqNumber = 32767; // 2^15 -1. +constexpr uint32_t kTimestampTicksPerMs = 90; +constexpr int kBitrateStatisticsWindowMs = 1000; + +constexpr size_t kMinFlexfecPacketsToStoreForPacing = 50; + +template <typename Extension> +constexpr RtpExtensionSize CreateExtensionSize() { + return {Extension::kId, Extension::kValueSizeBytes}; +} + +// Size info for header extensions that might be used in padding or FEC packets. +constexpr RtpExtensionSize kExtensionSizes[] = { + CreateExtensionSize<AbsoluteSendTime>(), + CreateExtensionSize<TransmissionOffset>(), + CreateExtensionSize<TransportSequenceNumber>(), + CreateExtensionSize<PlayoutDelayLimits>(), +}; + +const char* FrameTypeToString(FrameType frame_type) { + switch (frame_type) { + case kEmptyFrame: + return "empty"; + case kAudioFrameSpeech: return "audio_speech"; + case kAudioFrameCN: return "audio_cn"; + case kVideoFrameKey: return "video_key"; + case kVideoFrameDelta: return "video_delta"; + } + return ""; +} + +void CountPacket(RtpPacketCounter* counter, const RtpPacketToSend& packet) { + ++counter->packets; + counter->header_bytes += packet.headers_size(); + counter->padding_bytes += packet.padding_size(); + counter->payload_bytes += packet.payload_size(); +} + +} // namespace + +RTPSender::RTPSender( + bool audio, + Clock* clock, + Transport* transport, + RtpPacketSender* paced_sender, + FlexfecSender* flexfec_sender, + TransportSequenceNumberAllocator* sequence_number_allocator, + TransportFeedbackObserver* transport_feedback_observer, + BitrateStatisticsObserver* bitrate_callback, + FrameCountObserver* frame_count_observer, + SendSideDelayObserver* send_side_delay_observer, + RtcEventLog* event_log, + SendPacketObserver* send_packet_observer, + RateLimiter* retransmission_rate_limiter, + OverheadObserver* overhead_observer) + : clock_(clock), + // TODO(holmer): Remove this conversion? + clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()), + random_(clock_->TimeInMicroseconds()), + audio_configured_(audio), + audio_(audio ? new RTPSenderAudio(clock, this) : nullptr), + video_(audio ? nullptr : new RTPSenderVideo(clock, this, flexfec_sender)), + paced_sender_(paced_sender), + transport_sequence_number_allocator_(sequence_number_allocator), + transport_feedback_observer_(transport_feedback_observer), + last_capture_time_ms_sent_(0), + transport_(transport), + sending_media_(true), // Default to sending media. + max_packet_size_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP. + payload_type_(-1), + payload_type_map_(), + rtp_header_extension_map_(), + packet_history_(clock), + flexfec_packet_history_(clock), + // Statistics + rtp_stats_callback_(nullptr), + total_bitrate_sent_(kBitrateStatisticsWindowMs, + RateStatistics::kBpsScale), + nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale), + frame_count_observer_(frame_count_observer), + send_side_delay_observer_(send_side_delay_observer), + event_log_(event_log), + send_packet_observer_(send_packet_observer), + bitrate_callback_(bitrate_callback), + // RTP variables + remote_ssrc_(0), + sequence_number_forced_(false), + last_rtp_timestamp_(0), + capture_time_ms_(0), + last_timestamp_time_ms_(0), + media_has_been_sent_(false), + last_packet_marker_bit_(false), + csrcs_(), + rtx_(kRtxOff), + rtp_overhead_bytes_per_packet_(0), + retransmission_rate_limiter_(retransmission_rate_limiter), + overhead_observer_(overhead_observer), + send_side_bwe_with_overhead_( + webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")) { + // This random initialization is not intended to be cryptographic strong. + timestamp_offset_ = random_.Rand<uint32_t>(); + // Random start, 16 bits. Can't be 0. + sequence_number_rtx_ = random_.Rand(1, kMaxInitRtpSeqNumber); + sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber); + + // Store FlexFEC packets in the packet history data structure, so they can + // be found when paced. + if (flexfec_sender) { + flexfec_packet_history_.SetStorePacketsStatus( + true, kMinFlexfecPacketsToStoreForPacing); + } +} + +RTPSender::~RTPSender() { + // TODO(tommi): Use a thread checker to ensure the object is created and + // deleted on the same thread. At the moment this isn't possible due to + // voe::ChannelOwner in voice engine. To reproduce, run: + // voe_auto_test --automated --gtest_filter=*MixManyChannelsForStressOpus + + // TODO(tommi,holmer): We don't grab locks in the dtor before accessing member + // variables but we grab them in all other methods. (what's the design?) + // Start documenting what thread we're on in what method so that it's easier + // to understand performance attributes and possibly remove locks. + while (!payload_type_map_.empty()) { + std::map<int8_t, RtpUtility::Payload*>::iterator it = + payload_type_map_.begin(); + delete it->second; + payload_type_map_.erase(it); + } +} + +rtc::ArrayView<const RtpExtensionSize> RTPSender::FecExtensionSizes() { + return rtc::MakeArrayView(kExtensionSizes, arraysize(kExtensionSizes)); +} + +uint16_t RTPSender::ActualSendBitrateKbit() const { + rtc::CritScope cs(&statistics_crit_); + return static_cast<uint16_t>( + total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) / + 1000); +} + +uint32_t RTPSender::VideoBitrateSent() const { + if (video_) { + return video_->VideoBitrateSent(); + } + return 0; +} + +uint32_t RTPSender::FecOverheadRate() const { + if (video_) { + return video_->FecOverheadRate(); + } + return 0; +} + +uint32_t RTPSender::NackOverheadRate() const { + rtc::CritScope cs(&statistics_crit_); + return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0); +} + +int32_t RTPSender::SetRID(const char* rid) { + rtc::CritScope lock(&send_critsect_); + const size_t len = (rid && rid[0]) ? strlen(rid) : 0; + if (len) { + rtpStreamId.Set(rid, len); + } + return 0; +} + +int32_t RTPSender::SetMId(const char* mid) { + rtc::CritScope lock(&send_critsect_); + const size_t len = (mid && mid[0]) ? strlen(mid) : 0; + if (len) { + mId.Set(mid, len); + } + return 0; +} + +int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type, + uint8_t id) { + rtc::CritScope lock(&send_critsect_); + return rtp_header_extension_map_.RegisterByType(id, type) ? 0 : -1; +} + +bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) const { + rtc::CritScope lock(&send_critsect_); + return rtp_header_extension_map_.IsRegistered(type); +} + +int32_t RTPSender::DeregisterRtpHeaderExtension(RTPExtensionType type) { + rtc::CritScope lock(&send_critsect_); + return rtp_header_extension_map_.Deregister(type); +} + +int32_t RTPSender::RegisterPayload( + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + int8_t payload_number, + uint32_t frequency, + size_t channels, + uint32_t rate) { + RTC_DCHECK_LT(strlen(payload_name), RTP_PAYLOAD_NAME_SIZE); + rtc::CritScope lock(&send_critsect_); + + std::map<int8_t, RtpUtility::Payload*>::iterator it = + payload_type_map_.find(payload_number); + + if (payload_type_map_.end() != it) { + // We already use this payload type. + RtpUtility::Payload* payload = it->second; + RTC_DCHECK(payload); + + // Check if it's the same as we already have. + if (RtpUtility::StringCompare( + payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1)) { + if (audio_configured_ && payload->typeSpecific.is_audio()) { + auto& p = payload->typeSpecific.audio_payload(); + if (rtc::SafeEq(p.format.clockrate_hz, frequency) && + (p.rate == rate || p.rate == 0 || rate == 0)) { + p.rate = rate; + // Ensure that we update the rate if new or old is zero. + return 0; + } + } + if (!audio_configured_ && !payload->typeSpecific.is_audio()) { + return 0; + } + } + return -1; + } + int32_t ret_val = 0; + RtpUtility::Payload* payload = nullptr; + if (audio_configured_) { + // TODO(mflodman): Change to CreateAudioPayload and make static. + ret_val = audio_->RegisterAudioPayload(payload_name, payload_number, + frequency, channels, rate, &payload); + } else { + payload = video_->CreateVideoPayload(payload_name, payload_number); + } + if (payload) { + payload_type_map_[payload_number] = payload; + } + return ret_val; +} + +int32_t RTPSender::DeRegisterSendPayload(int8_t payload_type) { + rtc::CritScope lock(&send_critsect_); + + std::map<int8_t, RtpUtility::Payload*>::iterator it = + payload_type_map_.find(payload_type); + + if (payload_type_map_.end() == it) { + return -1; + } + RtpUtility::Payload* payload = it->second; + delete payload; + payload_type_map_.erase(it); + return 0; +} + +// TODO(nisse): Delete this method, only used internally and by test code. +void RTPSender::SetSendPayloadType(int8_t payload_type) { + rtc::CritScope lock(&send_critsect_); + payload_type_ = payload_type; +} + +void RTPSender::SetMaxRtpPacketSize(size_t max_packet_size) { + RTC_DCHECK_GE(max_packet_size, 100); + RTC_DCHECK_LE(max_packet_size, IP_PACKET_SIZE); + rtc::CritScope lock(&send_critsect_); + max_packet_size_ = max_packet_size; +} + +size_t RTPSender::MaxRtpPacketSize() const { + return max_packet_size_; +} + +void RTPSender::SetRtxStatus(int mode) { + rtc::CritScope lock(&send_critsect_); + rtx_ = mode; +} + +int RTPSender::RtxStatus() const { + rtc::CritScope lock(&send_critsect_); + return rtx_; +} + +void RTPSender::SetRtxSsrc(uint32_t ssrc) { + rtc::CritScope lock(&send_critsect_); + ssrc_rtx_.emplace(ssrc); +} + +uint32_t RTPSender::RtxSsrc() const { + rtc::CritScope lock(&send_critsect_); + RTC_DCHECK(ssrc_rtx_); + return *ssrc_rtx_; +} + +void RTPSender::SetRtxPayloadType(int payload_type, + int associated_payload_type) { + rtc::CritScope lock(&send_critsect_); + RTC_DCHECK_LE(payload_type, 127); + RTC_DCHECK_LE(associated_payload_type, 127); + if (payload_type < 0) { + RTC_LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type << "."; + return; + } + + rtx_payload_type_map_[associated_payload_type] = payload_type; +} + +int32_t RTPSender::CheckPayloadType(int8_t payload_type, + RtpVideoCodecTypes* video_type) { + rtc::CritScope lock(&send_critsect_); + + if (payload_type < 0) { + RTC_LOG(LS_ERROR) << "Invalid payload_type " << payload_type << "."; + return -1; + } + if (payload_type_ == payload_type) { + if (!audio_configured_) { + *video_type = video_->VideoCodecType(); + } + return 0; + } + std::map<int8_t, RtpUtility::Payload*>::iterator it = + payload_type_map_.find(payload_type); + if (it == payload_type_map_.end()) { + RTC_LOG(LS_WARNING) << "Payload type " << static_cast<int>(payload_type) + << " not registered."; + return -1; + } + SetSendPayloadType(payload_type); + RtpUtility::Payload* payload = it->second; + RTC_DCHECK(payload); + if (payload->typeSpecific.is_video() && !audio_configured_) { + video_->SetVideoCodecType( + payload->typeSpecific.video_payload().videoCodecType); + *video_type = payload->typeSpecific.video_payload().videoCodecType; + } + return 0; +} + +bool RTPSender::SendOutgoingData(FrameType frame_type, + int8_t payload_type, + uint32_t capture_timestamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* rtp_header, + uint32_t* transport_frame_id_out, + int64_t expected_retransmission_time_ms) { + uint32_t ssrc; + uint16_t sequence_number; + uint32_t rtp_timestamp; + { + // Drop this packet if we're not sending media packets. + rtc::CritScope lock(&send_critsect_); + RTC_DCHECK(ssrc_); + + ssrc = *ssrc_; + sequence_number = sequence_number_; + rtp_timestamp = timestamp_offset_ + capture_timestamp; + if (transport_frame_id_out) + *transport_frame_id_out = rtp_timestamp; + if (!sending_media_) + return true; + } + RtpVideoCodecTypes video_type = kRtpVideoGeneric; + if (CheckPayloadType(payload_type, &video_type) != 0) { + RTC_LOG(LS_ERROR) << "Don't send data with unknown payload type: " + << static_cast<int>(payload_type) << "."; + return false; + } + + switch (frame_type) { + case kAudioFrameSpeech: + case kAudioFrameCN: + RTC_CHECK(audio_configured_); + break; + case kVideoFrameKey: + case kVideoFrameDelta: + RTC_CHECK(!audio_configured_); + break; + case kEmptyFrame: + break; + } + + bool result; + if (audio_configured_) { + TRACE_EVENT_ASYNC_STEP1("webrtc", "Audio", rtp_timestamp, "Send", "type", + FrameTypeToString(frame_type)); + // The only known way to produce of RTPFragmentationHeader for audio is + // to use the AudioCodingModule directly. + RTC_DCHECK(fragmentation == nullptr); + result = audio_->SendAudio(frame_type, payload_type, rtp_timestamp, + payload_data, payload_size, &mId); + } else { + TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", capture_time_ms, + "Send", "type", FrameTypeToString(frame_type)); + if (frame_type == kEmptyFrame) + return true; + + if (rtp_header) { + playout_delay_oracle_.UpdateRequest(ssrc, rtp_header->playout_delay, + sequence_number); + } + + result = video_->SendVideo(video_type, frame_type, payload_type, + rtp_timestamp, capture_time_ms, payload_data, + payload_size, fragmentation, rtp_header, + expected_retransmission_time_ms, &rtpStreamId, + &mId); + } + + rtc::CritScope cs(&statistics_crit_); + // Note: This is currently only counting for video. + if (frame_type == kVideoFrameKey) { + ++frame_counts_.key_frames; + } else if (frame_type == kVideoFrameDelta) { + ++frame_counts_.delta_frames; + } + if (frame_count_observer_) { + frame_count_observer_->FrameCountUpdated(frame_counts_, ssrc); + } + + return result; +} + +size_t RTPSender::TrySendRedundantPayloads(size_t bytes_to_send, + const PacedPacketInfo& pacing_info) { + { + rtc::CritScope lock(&send_critsect_); + if (!sending_media_) + return 0; + if ((rtx_ & kRtxRedundantPayloads) == 0) + return 0; + } + + int bytes_left = static_cast<int>(bytes_to_send); + while (bytes_left > 0) { + std::unique_ptr<RtpPacketToSend> packet = + packet_history_.GetBestFittingPacket(bytes_left); + if (!packet) + break; + size_t payload_size = packet->payload_size(); + if (!PrepareAndSendPacket(std::move(packet), true, false, pacing_info)) + break; + bytes_left -= payload_size; + } + return bytes_to_send - bytes_left; +} + +size_t RTPSender::SendPadData(size_t bytes, + const PacedPacketInfo& pacing_info) { + size_t padding_bytes_in_packet; + size_t max_payload_size = max_packet_size_ - RtpHeaderLength(); + + if (audio_configured_) { + // Allow smaller padding packets for audio. + padding_bytes_in_packet = rtc::SafeClamp<size_t>( + bytes, kMinAudioPaddingLength, + rtc::SafeMin(max_payload_size, kMaxPaddingLength)); + } else { + // Always send full padding packets. This is accounted for by the + // RtpPacketSender, which will make sure we don't send too much padding even + // if a single packet is larger than requested. + // We do this to avoid frequently sending small packets on higher bitrates. + padding_bytes_in_packet = + rtc::SafeMin<size_t>(max_payload_size, kMaxPaddingLength); + } + size_t bytes_sent = 0; + while (bytes_sent < bytes) { + int64_t now_ms = clock_->TimeInMilliseconds(); + uint32_t ssrc; + uint32_t timestamp; + int64_t capture_time_ms; + uint16_t sequence_number; + int payload_type; + bool over_rtx; + { + rtc::CritScope lock(&send_critsect_); + if (!sending_media_) + break; + timestamp = last_rtp_timestamp_; + capture_time_ms = capture_time_ms_; + if (rtx_ == kRtxOff) { + if (payload_type_ == -1) + break; + // Without RTX we can't send padding in the middle of frames. + // For audio marker bits doesn't mark the end of a frame and frames + // are usually a single packet, so for now we don't apply this rule + // for audio. + if (!audio_configured_ && !last_packet_marker_bit_) { + break; + } + if (!ssrc_) { + RTC_LOG(LS_ERROR) << "SSRC unset."; + return 0; + } + + RTC_DCHECK(ssrc_); + ssrc = *ssrc_; + + sequence_number = sequence_number_; + ++sequence_number_; + payload_type = payload_type_; + over_rtx = false; + } else { + // Without abs-send-time or transport sequence number a media packet + // must be sent before padding so that the timestamps used for + // estimation are correct. + if (!media_has_been_sent_ && + !(rtp_header_extension_map_.IsRegistered(AbsoluteSendTime::kId) || + (rtp_header_extension_map_.IsRegistered( + TransportSequenceNumber::kId) && + transport_sequence_number_allocator_))) { + break; + } + // Only change change the timestamp of padding packets sent over RTX. + // Padding only packets over RTP has to be sent as part of a media + // frame (and therefore the same timestamp). + if (last_timestamp_time_ms_ > 0) { + timestamp += + (now_ms - last_timestamp_time_ms_) * kTimestampTicksPerMs; + if (capture_time_ms > 0) { + capture_time_ms += (now_ms - last_timestamp_time_ms_); + } + } + if (!ssrc_rtx_) { + RTC_LOG(LS_ERROR) << "RTX SSRC unset."; + return 0; + } + RTC_DCHECK(ssrc_rtx_); + ssrc = *ssrc_rtx_; + sequence_number = sequence_number_rtx_; + ++sequence_number_rtx_; + payload_type = rtx_payload_type_map_.begin()->second; + over_rtx = true; + } + } + + std::unique_ptr<RtpPacketToSend> padding_packet(new RtpPacketToSend(&rtp_header_extension_map_)); + padding_packet->SetPayloadType(payload_type); + padding_packet->SetMarker(false); + padding_packet->SetSequenceNumber(sequence_number); + padding_packet->SetTimestamp(timestamp); + padding_packet->SetSsrc(ssrc); + + if (capture_time_ms > 0) { + padding_packet->SetExtension<TransmissionOffset>( + (now_ms - capture_time_ms) * kTimestampTicksPerMs); + } + padding_packet->SetExtension<AbsoluteSendTime>( + AbsoluteSendTime::MsTo24Bits(now_ms)); + PacketOptions options; + bool has_transport_seq_num = + UpdateTransportSequenceNumber(padding_packet.get(), &options.packet_id); + padding_packet->SetPadding(padding_bytes_in_packet, &random_); + + if (has_transport_seq_num) { + AddPacketToTransportFeedback(options.packet_id, *padding_packet, + pacing_info); + } + + if (!SendPacketToNetwork(*padding_packet, options, pacing_info)) + break; + bytes_sent += padding_bytes_in_packet; + UpdateRtpStats(*padding_packet, over_rtx, false); + + packet_history_.PutRtpPacket(std::move(padding_packet), + kAllowRetransmission, + true); + } + + return bytes_sent; +} + +void RTPSender::SetStorePacketsStatus(bool enable, uint16_t number_to_store) { + packet_history_.SetStorePacketsStatus(enable, number_to_store); +} + +bool RTPSender::StorePackets() const { + return packet_history_.StorePackets(); +} + +int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) { + std::unique_ptr<RtpPacketToSend> packet = + packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true); + if (!packet) { + // Packet not found. + return 0; + } + + // Check if we're overusing retransmission bitrate. + // TODO(sprang): Add histograms for nack success or failure reasons. + RTC_DCHECK(retransmission_rate_limiter_); + if (!retransmission_rate_limiter_->TryUseRate(packet->size())) + return -1; + + if (paced_sender_) { + // Convert from TickTime to Clock since capture_time_ms is based on + // TickTime. + int64_t corrected_capture_tims_ms = + packet->capture_time_ms() + clock_delta_ms_; + paced_sender_->InsertPacket(RtpPacketSender::kNormalPriority, + packet->Ssrc(), packet->SequenceNumber(), + corrected_capture_tims_ms, + packet->payload_size(), true); + + return packet->size(); + } + bool rtx = (RtxStatus() & kRtxRetransmitted) > 0; + int32_t packet_size = static_cast<int32_t>(packet->size()); + if (!PrepareAndSendPacket(std::move(packet), rtx, true, PacedPacketInfo())) + return -1; + return packet_size; +} + +bool RTPSender::SendPacketToNetwork(const RtpPacketToSend& packet, + const PacketOptions& options, + const PacedPacketInfo& pacing_info) { + int bytes_sent = -1; + if (transport_) { + UpdateRtpOverhead(packet); + bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options) + ? static_cast<int>(packet.size()) + : -1; + if (event_log_ && bytes_sent > 0) { + event_log_->Log(rtc::MakeUnique<RtcEventRtpPacketOutgoing>( + packet, pacing_info.probe_cluster_id)); + } + } + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "RTPSender::SendPacketToNetwork", "size", packet.size(), + "sent", bytes_sent); + // TODO(pwestin): Add a separate bitrate for sent bitrate after pacer. + if (bytes_sent <= 0) { + RTC_LOG(LS_WARNING) << "Transport failed to send packet."; + return false; + } + return true; +} + +int RTPSender::SelectiveRetransmissions() const { + if (!video_) + return -1; + return video_->SelectiveRetransmissions(); +} + +int RTPSender::SetSelectiveRetransmissions(uint8_t settings) { + if (!video_) + return -1; + video_->SetSelectiveRetransmissions(settings); + return 0; +} + +void RTPSender::OnReceivedNack( + const std::vector<uint16_t>& nack_sequence_numbers, + int64_t avg_rtt) { + TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "RTPSender::OnReceivedNACK", "num_seqnum", + nack_sequence_numbers.size(), "avg_rtt", avg_rtt); + for (uint16_t seq_no : nack_sequence_numbers) { + const int32_t bytes_sent = ReSendPacket(seq_no, 5 + avg_rtt); + if (bytes_sent < 0) { + // Failed to send one Sequence number. Give up the rest in this nack. + RTC_LOG(LS_WARNING) << "Failed resending RTP packet " << seq_no + << ", Discard rest of packets."; + break; + } + } +} + +void RTPSender::OnReceivedRtcpReportBlocks( + const ReportBlockList& report_blocks) { + playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks); +} + +// Called from pacer when we can send the packet. +bool RTPSender::TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission, + const PacedPacketInfo& pacing_info) { + if (!SendingMedia()) + return true; + + std::unique_ptr<RtpPacketToSend> packet; + if (ssrc == SSRC()) { + packet = packet_history_.GetPacketAndSetSendTime(sequence_number, 0, + retransmission); + } else if (ssrc == FlexfecSsrc()) { + packet = flexfec_packet_history_.GetPacketAndSetSendTime(sequence_number, 0, + retransmission); + } + + if (!packet) { + // Packet cannot be found. + return true; + } + + return PrepareAndSendPacket( + std::move(packet), + retransmission && (RtxStatus() & kRtxRetransmitted) > 0, retransmission, + pacing_info); +} + +bool RTPSender::PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet, + bool send_over_rtx, + bool is_retransmit, + const PacedPacketInfo& pacing_info) { + RTC_DCHECK(packet); + int64_t capture_time_ms = packet->capture_time_ms(); + RtpPacketToSend* packet_to_send = packet.get(); + + if (!is_retransmit && packet->Marker()) { + TRACE_EVENT_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PacedSend", + capture_time_ms); + } + + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "PrepareAndSendPacket", "timestamp", packet->Timestamp(), + "seqnum", packet->SequenceNumber()); + + std::unique_ptr<RtpPacketToSend> packet_rtx; + if (send_over_rtx) { + packet_rtx = BuildRtxPacket(*packet); + if (!packet_rtx) + return false; + packet_to_send = packet_rtx.get(); + } + + // Bug webrtc:7859. While FEC is invoked from rtp_sender_video, and not after + // the pacer, these modifications of the header below are happening after the + // FEC protection packets are calculated. This will corrupt recovered packets + // at the same place. It's not an issue for extensions, which are present in + // all the packets (their content just may be incorrect on recovered packets). + // In case of VideoTimingExtension, since it's present not in every packet, + // data after rtp header may be corrupted if these packets are protected by + // the FEC. + int64_t now_ms = clock_->TimeInMilliseconds(); + int64_t diff_ms = now_ms - capture_time_ms; + packet_to_send->SetExtension<TransmissionOffset>(kTimestampTicksPerMs * + diff_ms); + packet_to_send->SetExtension<AbsoluteSendTime>( + AbsoluteSendTime::MsTo24Bits(now_ms)); + + if (packet_to_send->HasExtension<VideoTimingExtension>()) + packet_to_send->set_pacer_exit_time_ms(now_ms); + + PacketOptions options; + if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id)) { + AddPacketToTransportFeedback(options.packet_id, *packet_to_send, + pacing_info); + } + + if (!is_retransmit && !send_over_rtx) { + UpdateDelayStatistics(packet->capture_time_ms(), now_ms); + UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(), + packet->Ssrc()); + } + + if (!SendPacketToNetwork(*packet_to_send, options, pacing_info)) + return false; + + { + rtc::CritScope lock(&send_critsect_); + media_has_been_sent_ = true; + } + UpdateRtpStats(*packet_to_send, send_over_rtx, is_retransmit); + return true; +} + +void RTPSender::UpdateRtpStats(const RtpPacketToSend& packet, + bool is_rtx, + bool is_retransmit) { + int64_t now_ms = clock_->TimeInMilliseconds(); + + rtc::CritScope lock(&statistics_crit_); + StreamDataCounters* counters = is_rtx ? &rtx_rtp_stats_ : &rtp_stats_; + + total_bitrate_sent_.Update(packet.size(), now_ms); + + if (counters->first_packet_time_ms == -1) + counters->first_packet_time_ms = now_ms; + + if (IsFecPacket(packet)) + CountPacket(&counters->fec, packet); + + if (is_retransmit) { + CountPacket(&counters->retransmitted, packet); + nack_bitrate_sent_.Update(packet.size(), now_ms); + } + CountPacket(&counters->transmitted, packet); + + if (rtp_stats_callback_) + rtp_stats_callback_->DataCountersUpdated(*counters, packet.Ssrc()); +} + +bool RTPSender::IsFecPacket(const RtpPacketToSend& packet) const { + if (!video_) + return false; + + // FlexFEC. + if (packet.Ssrc() == FlexfecSsrc()) + return true; + + // RED+ULPFEC. + int pt_red; + int pt_fec; + video_->GetUlpfecConfig(&pt_red, &pt_fec); + return static_cast<int>(packet.PayloadType()) == pt_red && + static_cast<int>(packet.payload()[0]) == pt_fec; +} + +size_t RTPSender::TimeToSendPadding(size_t bytes, + const PacedPacketInfo& pacing_info) { + if (bytes == 0) + return 0; + size_t bytes_sent = TrySendRedundantPayloads(bytes, pacing_info); + if (bytes_sent < bytes) + bytes_sent += SendPadData(bytes - bytes_sent, pacing_info); + return bytes_sent; +} + +bool RTPSender::SendToNetwork(std::unique_ptr<RtpPacketToSend> packet, + StorageType storage, + RtpPacketSender::Priority priority) { + RTC_DCHECK(packet); + int64_t now_ms = clock_->TimeInMilliseconds(); + + // |capture_time_ms| <= 0 is considered invalid. + // TODO(holmer): This should be changed all over Video Engine so that negative + // time is consider invalid, while 0 is considered a valid time. + if (packet->capture_time_ms() > 0) { + packet->SetExtension<TransmissionOffset>( + kTimestampTicksPerMs * (now_ms - packet->capture_time_ms())); + if (packet->HasExtension<VideoTimingExtension>()) + packet->set_pacer_exit_time_ms(now_ms); + } + packet->SetExtension<AbsoluteSendTime>(AbsoluteSendTime::MsTo24Bits(now_ms)); + + if (video_) { + BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms, + ActualSendBitrateKbit(), packet->Ssrc()); + BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms, + FecOverheadRate() / 1000, packet->Ssrc()); + BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms, + NackOverheadRate() / 1000, packet->Ssrc()); + } else { + BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioTotBitrate_kbps", now_ms, + ActualSendBitrateKbit(), packet->Ssrc()); + BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioNackBitrate_kbps", now_ms, + NackOverheadRate() / 1000, packet->Ssrc()); + } + + uint32_t ssrc = packet->Ssrc(); + rtc::Optional<uint32_t> flexfec_ssrc = FlexfecSsrc(); + if (paced_sender_) { + uint16_t seq_no = packet->SequenceNumber(); + // Correct offset between implementations of millisecond time stamps in + // TickTime and Clock. + int64_t corrected_time_ms = packet->capture_time_ms() + clock_delta_ms_; + size_t payload_length = packet->payload_size(); + if (ssrc == flexfec_ssrc) { + // Store FlexFEC packets in the history here, so they can be found + // when the pacer calls TimeToSendPacket. + flexfec_packet_history_.PutRtpPacket(std::move(packet), storage, false); + } else { + packet_history_.PutRtpPacket(std::move(packet), storage, false); + } + + paced_sender_->InsertPacket(priority, ssrc, seq_no, corrected_time_ms, + payload_length, false); + if (last_capture_time_ms_sent_ == 0 || + corrected_time_ms > last_capture_time_ms_sent_) { + last_capture_time_ms_sent_ = corrected_time_ms; + TRACE_EVENT_ASYNC_BEGIN1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "PacedSend", corrected_time_ms, + "capture_time_ms", corrected_time_ms); + } + return true; + } + + PacketOptions options; + if (UpdateTransportSequenceNumber(packet.get(), &options.packet_id)) { + AddPacketToTransportFeedback(options.packet_id, *packet.get(), + PacedPacketInfo()); + } + + UpdateDelayStatistics(packet->capture_time_ms(), now_ms); + UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(), + packet->Ssrc()); + + bool sent = SendPacketToNetwork(*packet, options, PacedPacketInfo()); + + if (sent) { + { + rtc::CritScope lock(&send_critsect_); + media_has_been_sent_ = true; + } + UpdateRtpStats(*packet, false, false); + } + + // To support retransmissions, we store the media packet as sent in the + // packet history (even if send failed). + if (storage == kAllowRetransmission) { + // TODO(brandtr): Uncomment the DCHECK line below when |ssrc_| cannot + // change after the first packet has been sent. For more details, see + // https://bugs.chromium.org/p/webrtc/issues/detail?id=6887. + // RTC_DCHECK_EQ(ssrc, SSRC()); + packet_history_.PutRtpPacket(std::move(packet), storage, true); + } + + return sent; +} + +void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) { + if (!send_side_delay_observer_ || capture_time_ms <= 0) + return; + + uint32_t ssrc; + int64_t avg_delay_ms = 0; + int max_delay_ms = 0; + { + rtc::CritScope lock(&send_critsect_); + if (!ssrc_) + return; + ssrc = *ssrc_; + } + { + rtc::CritScope cs(&statistics_crit_); + // TODO(holmer): Compute this iteratively instead. + send_delays_[now_ms] = now_ms - capture_time_ms; + send_delays_.erase(send_delays_.begin(), + send_delays_.lower_bound(now_ms - + kSendSideDelayWindowMs)); + int num_delays = 0; + for (auto it = send_delays_.upper_bound(now_ms - kSendSideDelayWindowMs); + it != send_delays_.end(); ++it) { + max_delay_ms = std::max(max_delay_ms, it->second); + avg_delay_ms += it->second; + ++num_delays; + } + if (num_delays == 0) + return; + avg_delay_ms = (avg_delay_ms + num_delays / 2) / num_delays; + } + send_side_delay_observer_->SendSideDelayUpdated( + rtc::dchecked_cast<int>(avg_delay_ms), max_delay_ms, ssrc); +} + +void RTPSender::UpdateOnSendPacket(int packet_id, + int64_t capture_time_ms, + uint32_t ssrc) { + if (!send_packet_observer_ || capture_time_ms <= 0 || packet_id == -1) + return; + + send_packet_observer_->OnSendPacket(packet_id, capture_time_ms, ssrc); +} + +void RTPSender::ProcessBitrate() { + if (!bitrate_callback_) + return; + int64_t now_ms = clock_->TimeInMilliseconds(); + uint32_t ssrc; + { + rtc::CritScope lock(&send_critsect_); + if (!ssrc_) + return; + ssrc = *ssrc_; + } + + rtc::CritScope lock(&statistics_crit_); + bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0), + nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc); +} + +size_t RTPSender::RtpHeaderLength() const { + rtc::CritScope lock(&send_critsect_); + size_t rtp_header_length = kRtpHeaderLength; + rtp_header_length += sizeof(uint32_t) * csrcs_.size(); + rtp_header_length += + rtp_header_extension_map_.GetTotalLengthInBytes(kExtensionSizes); + return rtp_header_length; +} + +uint16_t RTPSender::AllocateSequenceNumber(uint16_t packets_to_send) { + rtc::CritScope lock(&send_critsect_); + uint16_t first_allocated_sequence_number = sequence_number_; + sequence_number_ += packets_to_send; + return first_allocated_sequence_number; +} + +void RTPSender::GetDataCounters(StreamDataCounters* rtp_stats, + StreamDataCounters* rtx_stats) const { + rtc::CritScope lock(&statistics_crit_); + *rtp_stats = rtp_stats_; + *rtx_stats = rtx_rtp_stats_; +} + +std::unique_ptr<RtpPacketToSend> RTPSender::AllocatePacket() const { + rtc::CritScope lock(&send_critsect_); + std::unique_ptr<RtpPacketToSend> packet( + new RtpPacketToSend(&rtp_header_extension_map_, max_packet_size_)); + RTC_DCHECK(ssrc_); + packet->SetSsrc(*ssrc_); + packet->SetCsrcs(csrcs_); + // Reserve extensions, if registered, RtpSender set in SendToNetwork. + packet->ReserveExtension<AbsoluteSendTime>(); + packet->ReserveExtension<TransmissionOffset>(); + packet->ReserveExtension<TransportSequenceNumber>(); + if (playout_delay_oracle_.send_playout_delay()) { + packet->SetExtension<PlayoutDelayLimits>( + playout_delay_oracle_.playout_delay()); + } + return packet; +} + +bool RTPSender::AssignSequenceNumber(RtpPacketToSend* packet) { + rtc::CritScope lock(&send_critsect_); + if (!sending_media_) + return false; + RTC_DCHECK(packet->Ssrc() == ssrc_); + packet->SetSequenceNumber(sequence_number_++); + + // Remember marker bit to determine if padding can be inserted with + // sequence number following |packet|. + last_packet_marker_bit_ = packet->Marker(); + // Save timestamps to generate timestamp field and extensions for the padding. + last_rtp_timestamp_ = packet->Timestamp(); + last_timestamp_time_ms_ = clock_->TimeInMilliseconds(); + capture_time_ms_ = packet->capture_time_ms(); + return true; +} + +bool RTPSender::UpdateTransportSequenceNumber(RtpPacketToSend* packet, + int* packet_id) const { + RTC_DCHECK(packet); + RTC_DCHECK(packet_id); + rtc::CritScope lock(&send_critsect_); + if (!rtp_header_extension_map_.IsRegistered(TransportSequenceNumber::kId)) + return false; + + if (!transport_sequence_number_allocator_) + return false; + + *packet_id = transport_sequence_number_allocator_->AllocateSequenceNumber(); + + if (!packet->SetExtension<TransportSequenceNumber>(*packet_id)) + return false; + + return true; +} + +void RTPSender::SetSendingMediaStatus(bool enabled) { + rtc::CritScope lock(&send_critsect_); + sending_media_ = enabled; +} + +bool RTPSender::SendingMedia() const { + rtc::CritScope lock(&send_critsect_); + return sending_media_; +} + +void RTPSender::SetTimestampOffset(uint32_t timestamp) { + rtc::CritScope lock(&send_critsect_); + timestamp_offset_ = timestamp; +} + +uint32_t RTPSender::TimestampOffset() const { + rtc::CritScope lock(&send_critsect_); + return timestamp_offset_; +} + +void RTPSender::SetSSRC(uint32_t ssrc) { + // This is configured via the API. + rtc::CritScope lock(&send_critsect_); + + if (ssrc_ == ssrc) { + return; // Since it's same ssrc, don't reset anything. + } + ssrc_.emplace(ssrc); + if (!sequence_number_forced_) { + sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber); + } +} + +uint32_t RTPSender::SSRC() const { + rtc::CritScope lock(&send_critsect_); + RTC_DCHECK(ssrc_); + return *ssrc_; +} + +rtc::Optional<uint32_t> RTPSender::FlexfecSsrc() const { + if (video_) { + return video_->FlexfecSsrc(); + } + return rtc::nullopt; +} + +void RTPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) { + RTC_DCHECK_LE(csrcs.size(), kRtpCsrcSize); + rtc::CritScope lock(&send_critsect_); + csrcs_ = csrcs; +} + +void RTPSender::SetSequenceNumber(uint16_t seq) { + rtc::CritScope lock(&send_critsect_); + sequence_number_forced_ = true; + sequence_number_ = seq; +} + +uint16_t RTPSender::SequenceNumber() const { + rtc::CritScope lock(&send_critsect_); + return sequence_number_; +} + +// Audio. +int32_t RTPSender::SendTelephoneEvent(uint8_t key, + uint16_t time_ms, + uint8_t level) { + if (!audio_configured_) { + return -1; + } + return audio_->SendTelephoneEvent(key, time_ms, level); +} + +int32_t RTPSender::SetAudioLevel(uint8_t level_d_bov) { + return audio_->SetAudioLevel(level_d_bov); +} + +RtpVideoCodecTypes RTPSender::VideoCodecType() const { + RTC_DCHECK(!audio_configured_) << "Sender is an audio stream!"; + return video_->VideoCodecType(); +} + +void RTPSender::SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) { + RTC_DCHECK(!audio_configured_); + video_->SetUlpfecConfig(red_payload_type, ulpfec_payload_type); +} + +bool RTPSender::SetFecParameters(const FecProtectionParams& delta_params, + const FecProtectionParams& key_params) { + if (audio_configured_) { + return false; + } + video_->SetFecParameters(delta_params, key_params); + return true; +} + +static void CopyHeaderAndExtensionsToRtxPacket(const RtpPacketToSend& packet, + RtpPacketToSend* rtx_packet) { + // Set the relevant fixed packet headers. The following are not set: + // * Payload type - it is replaced in rtx packets. + // * Sequence number - RTX has a separate sequence numbering. + // * SSRC - RTX stream has its own SSRC. + rtx_packet->SetMarker(packet.Marker()); + rtx_packet->SetTimestamp(packet.Timestamp()); + + // Set the variable fields in the packet header: + // * CSRCs - must be set before header extensions. + // * Header extensions - replace Rid header with RepairedRid header. + const std::vector<uint32_t> csrcs = packet.Csrcs(); + rtx_packet->SetCsrcs(csrcs); + for (int extension_num = kRtpExtensionNone + 1; + extension_num < kRtpExtensionNumberOfExtensions; ++extension_num) { + auto extension = static_cast<RTPExtensionType>(extension_num); + + // Stream ID header extensions (MID, RSID) are sent per-SSRC. Since RTX + // operates on a different SSRC, the presence and values of these header + // extensions should be determined separately and not blindly copied. + if (extension == kRtpExtensionMid || + extension == kRtpExtensionRtpStreamId) { + continue; + } + + rtc::ArrayView<const uint8_t> source = packet.FindExtension(extension); + + // Empty extensions should be supported, so not checking |source.empty()|. + // TODO: But this does not work in Mozilla's version of libwebrtc. Remove + // this check with the next update from tip of libwebrtc. + if (source.empty()) { + continue; + } + + rtc::ArrayView<uint8_t> destination = + rtx_packet->AllocateExtension(extension, source.size()); + + // Could happen if any: + // 1. Extension has 0 length. + // 2. Extension is not registered in destination. + // 3. Allocating extension in destination failed. + if (destination.empty() || source.size() != destination.size()) { + continue; + } + + std::memcpy(destination.begin(), source.begin(), destination.size()); + } +} + +std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket( + const RtpPacketToSend& packet) { + // TODO(danilchap): Create rtx packet with extra capacity for SRTP + // when transport interface would be updated to take buffer class. + std::unique_ptr<RtpPacketToSend> rtx_packet(new RtpPacketToSend( + &rtp_header_extension_map_, max_packet_size_)); + // Add original RTP header. + { + rtc::CritScope lock(&send_critsect_); + if (!sending_media_) + return nullptr; + + RTC_DCHECK(ssrc_rtx_); + + // Replace payload type. + auto kv = rtx_payload_type_map_.find(packet.PayloadType()); + if (kv == rtx_payload_type_map_.end()) + return nullptr; + rtx_packet->SetPayloadType(kv->second); + + // Replace sequence number. + rtx_packet->SetSequenceNumber(sequence_number_rtx_++); + + // Replace SSRC. + rtx_packet->SetSsrc(*ssrc_rtx_); + + CopyHeaderAndExtensionsToRtxPacket(packet, rtx_packet.get()); + + // Copy rtp-stream-id from packet to repaired-rtp-stream-id + if (rtp_header_extension_map_.IsRegistered(kRtpExtensionRtpStreamId) && + rtp_header_extension_map_.IsRegistered(kRtpExtensionRepairedRtpStreamId)) { + std::string rid; + if (packet.GetExtension<RtpStreamId>(&rid)) { + rtx_packet->SetExtension<RepairedRtpStreamId>(rid); + } + } + + // Copy mid from packet + if (rtp_header_extension_map_.IsRegistered(kRtpExtensionMid)) { + std::string mid; + if (packet.GetExtension<RtpMid>(&mid)) { + rtx_packet->SetExtension<RtpMid>(mid); + } + } + } + uint8_t* rtx_payload = + rtx_packet->AllocatePayload(packet.payload_size() + kRtxHeaderSize); + RTC_DCHECK(rtx_payload); + // Add OSN (original sequence number). + ByteWriter<uint16_t>::WriteBigEndian(rtx_payload, packet.SequenceNumber()); + + // Add original payload data. + auto payload = packet.payload(); + memcpy(rtx_payload + kRtxHeaderSize, payload.data(), payload.size()); + + return rtx_packet; +} + +void RTPSender::RegisterRtpStatisticsCallback( + StreamDataCountersCallback* callback) { + rtc::CritScope cs(&statistics_crit_); + rtp_stats_callback_ = callback; +} + +StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const { + rtc::CritScope cs(&statistics_crit_); + return rtp_stats_callback_; +} + +uint32_t RTPSender::BitrateSent() const { + rtc::CritScope cs(&statistics_crit_); + return total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0); +} + +void RTPSender::SetRtpState(const RtpState& rtp_state) { + rtc::CritScope lock(&send_critsect_); + sequence_number_ = rtp_state.sequence_number; + sequence_number_forced_ = true; + timestamp_offset_ = rtp_state.start_timestamp; + last_rtp_timestamp_ = rtp_state.timestamp; + capture_time_ms_ = rtp_state.capture_time_ms; + last_timestamp_time_ms_ = rtp_state.last_timestamp_time_ms; + media_has_been_sent_ = rtp_state.media_has_been_sent; +} + +RtpState RTPSender::GetRtpState() const { + rtc::CritScope lock(&send_critsect_); + + RtpState state; + state.sequence_number = sequence_number_; + state.start_timestamp = timestamp_offset_; + state.timestamp = last_rtp_timestamp_; + state.capture_time_ms = capture_time_ms_; + state.last_timestamp_time_ms = last_timestamp_time_ms_; + state.media_has_been_sent = media_has_been_sent_; + + return state; +} + +void RTPSender::SetRtxRtpState(const RtpState& rtp_state) { + rtc::CritScope lock(&send_critsect_); + sequence_number_rtx_ = rtp_state.sequence_number; +} + +RtpState RTPSender::GetRtxRtpState() const { + rtc::CritScope lock(&send_critsect_); + + RtpState state; + state.sequence_number = sequence_number_rtx_; + state.start_timestamp = timestamp_offset_; + + return state; +} + +void RTPSender::AddPacketToTransportFeedback( + uint16_t packet_id, + const RtpPacketToSend& packet, + const PacedPacketInfo& pacing_info) { + size_t packet_size = packet.payload_size() + packet.padding_size(); + if (send_side_bwe_with_overhead_) { + packet_size = packet.size(); + } + + if (transport_feedback_observer_) { + transport_feedback_observer_->AddPacket(SSRC(), packet_id, packet_size, + pacing_info); + } +} + +void RTPSender::UpdateRtpOverhead(const RtpPacketToSend& packet) { + if (!overhead_observer_) + return; + size_t overhead_bytes_per_packet; + { + rtc::CritScope lock(&send_critsect_); + if (rtp_overhead_bytes_per_packet_ == packet.headers_size()) { + return; + } + rtp_overhead_bytes_per_packet_ = packet.headers_size(); + overhead_bytes_per_packet = rtp_overhead_bytes_per_packet_; + } + overhead_observer_->OnOverheadChanged(overhead_bytes_per_packet); +} + +int64_t RTPSender::LastTimestampTimeMs() const { + rtc::CritScope lock(&send_critsect_); + return last_timestamp_time_ms_; +} + +void RTPSender::SendKeepAlive(uint8_t payload_type) { + std::unique_ptr<RtpPacketToSend> packet = AllocatePacket(); + packet->SetPayloadType(payload_type); + // Set marker bit and timestamps in the same manner as plain padding packets. + packet->SetMarker(false); + { + rtc::CritScope lock(&send_critsect_); + packet->SetTimestamp(last_rtp_timestamp_); + packet->set_capture_time_ms(capture_time_ms_); + } + AssignSequenceNumber(packet.get()); + SendToNetwork(std::move(packet), StorageType::kDontRetransmit, + RtpPacketSender::Priority::kLowPriority); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.h new file mode 100644 index 0000000000..6f79d96d9b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -0,0 +1,344 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_ + +#include <map> +#include <memory> +#include <utility> +#include <vector> + +#include "api/array_view.h" +#include "api/call/transport.h" +#include "api/optional.h" +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/flexfec_sender.h" +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/playout_delay_oracle.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_utility.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/deprecation.h" +#include "rtc_base/random.h" +#include "rtc_base/rate_statistics.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class OverheadObserver; +class RateLimiter; +class RtcEventLog; +class RtpPacketToSend; +class RTPSenderAudio; +class RTPSenderVideo; + +class RTPSender { + public: + RTPSender(bool audio, + Clock* clock, + Transport* transport, + RtpPacketSender* paced_sender, + // TODO(brandtr): Remove |flexfec_sender| when that is hooked up + // to PacedSender instead. + FlexfecSender* flexfec_sender, + TransportSequenceNumberAllocator* sequence_number_allocator, + TransportFeedbackObserver* transport_feedback_callback, + BitrateStatisticsObserver* bitrate_callback, + FrameCountObserver* frame_count_observer, + SendSideDelayObserver* send_side_delay_observer, + RtcEventLog* event_log, + SendPacketObserver* send_packet_observer, + RateLimiter* nack_rate_limiter, + OverheadObserver* overhead_observer); + + ~RTPSender(); + + void ProcessBitrate(); + + uint16_t ActualSendBitrateKbit() const; + + uint32_t VideoBitrateSent() const; + uint32_t FecOverheadRate() const; + uint32_t NackOverheadRate() const; + + int32_t RegisterPayload(const char* payload_name, + const int8_t payload_type, + const uint32_t frequency, + const size_t channels, + const uint32_t rate); + + int32_t DeRegisterSendPayload(const int8_t payload_type); + + void SetSendPayloadType(int8_t payload_type); + + void SetSendingMediaStatus(bool enabled); + bool SendingMedia() const; + + void GetDataCounters(StreamDataCounters* rtp_stats, + StreamDataCounters* rtx_stats) const; + + uint32_t TimestampOffset() const; + void SetTimestampOffset(uint32_t timestamp); + + void SetSSRC(uint32_t ssrc); + + uint16_t SequenceNumber() const; + void SetSequenceNumber(uint16_t seq); + + void SetCsrcs(const std::vector<uint32_t>& csrcs); + + void SetMaxRtpPacketSize(size_t max_packet_size); + + bool SendOutgoingData(FrameType frame_type, + int8_t payload_type, + uint32_t timestamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* rtp_header, + uint32_t* transport_frame_id_out, + int64_t expected_retransmission_time_ms); + + int32_t SetRID(const char* rid); + int32_t SetMId(const char* mid); + + // RTP header extension + int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id); + bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) const; + int32_t DeregisterRtpHeaderExtension(RTPExtensionType type); + + bool TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission, + const PacedPacketInfo& pacing_info); + size_t TimeToSendPadding(size_t bytes, const PacedPacketInfo& pacing_info); + + // NACK. + int SelectiveRetransmissions() const; + int SetSelectiveRetransmissions(uint8_t settings); + void OnReceivedNack(const std::vector<uint16_t>& nack_sequence_numbers, + int64_t avg_rtt); + + void SetStorePacketsStatus(bool enable, uint16_t number_to_store); + + bool StorePackets() const; + + int32_t ReSendPacket(uint16_t packet_id, int64_t min_resend_time = 0); + + // Feedback to decide when to stop sending playout delay. + void OnReceivedRtcpReportBlocks(const ReportBlockList& report_blocks); + + // RTX. + void SetRtxStatus(int mode); + int RtxStatus() const; + + uint32_t RtxSsrc() const; + void SetRtxSsrc(uint32_t ssrc); + + void SetRtxPayloadType(int payload_type, int associated_payload_type); + + // Size info for header extensions used by FEC packets. + static rtc::ArrayView<const RtpExtensionSize> FecExtensionSizes(); + + // Create empty packet, fills ssrc, csrcs and reserve place for header + // extensions RtpSender updates before sending. + std::unique_ptr<RtpPacketToSend> AllocatePacket() const; + // Allocate sequence number for provided packet. + // Save packet's fields to generate padding that doesn't break media stream. + // Return false if sending was turned off. + bool AssignSequenceNumber(RtpPacketToSend* packet); + + // Used for padding and FEC packets only. + size_t RtpHeaderLength() const; + uint16_t AllocateSequenceNumber(uint16_t packets_to_send); + // Including RTP headers. + size_t MaxRtpPacketSize() const; + + uint32_t SSRC() const; + + rtc::Optional<uint32_t> FlexfecSsrc() const; + + bool SendToNetwork(std::unique_ptr<RtpPacketToSend> packet, + StorageType storage, + RtpPacketSender::Priority priority); + + // Audio. + + // Send a DTMF tone using RFC 2833 (4733). + int32_t SendTelephoneEvent(uint8_t key, uint16_t time_ms, uint8_t level); + + // Store the audio level in d_bov for + // header-extension-for-audio-level-indication. + int32_t SetAudioLevel(uint8_t level_d_bov); + + RtpVideoCodecTypes VideoCodecType() const; + + uint32_t MaxConfiguredBitrateVideo() const; + + // ULPFEC. + void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type); + + bool SetFecParameters(const FecProtectionParams& delta_params, + const FecProtectionParams& key_params); + + // Called on update of RTP statistics. + void RegisterRtpStatisticsCallback(StreamDataCountersCallback* callback); + StreamDataCountersCallback* GetRtpStatisticsCallback() const; + + uint32_t BitrateSent() const; + + void SetRtpState(const RtpState& rtp_state); + RtpState GetRtpState() const; + void SetRtxRtpState(const RtpState& rtp_state); + RtpState GetRtxRtpState() const; + + int64_t LastTimestampTimeMs() const; + void SendKeepAlive(uint8_t payload_type); + + protected: + int32_t CheckPayloadType(int8_t payload_type, RtpVideoCodecTypes* video_type); + + private: + // Maps capture time in milliseconds to send-side delay in milliseconds. + // Send-side delay is the difference between transmission time and capture + // time. + typedef std::map<int64_t, int> SendDelayMap; + + size_t SendPadData(size_t bytes, const PacedPacketInfo& pacing_info); + + bool PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet, + bool send_over_rtx, + bool is_retransmit, + const PacedPacketInfo& pacing_info); + + // Return the number of bytes sent. Note that both of these functions may + // return a larger value that their argument. + size_t TrySendRedundantPayloads(size_t bytes, + const PacedPacketInfo& pacing_info); + + std::unique_ptr<RtpPacketToSend> BuildRtxPacket( + const RtpPacketToSend& packet); + + bool SendPacketToNetwork(const RtpPacketToSend& packet, + const PacketOptions& options, + const PacedPacketInfo& pacing_info); + + void UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms); + void UpdateOnSendPacket(int packet_id, + int64_t capture_time_ms, + uint32_t ssrc); + + bool UpdateTransportSequenceNumber(RtpPacketToSend* packet, + int* packet_id) const; + + void UpdateRtpStats(const RtpPacketToSend& packet, + bool is_rtx, + bool is_retransmit); + bool IsFecPacket(const RtpPacketToSend& packet) const; + + void AddPacketToTransportFeedback(uint16_t packet_id, + const RtpPacketToSend& packet, + const PacedPacketInfo& pacing_info); + + void UpdateRtpOverhead(const RtpPacketToSend& packet); + + Clock* const clock_; + const int64_t clock_delta_ms_; + Random random_ RTC_GUARDED_BY(send_critsect_); + + const bool audio_configured_; + const std::unique_ptr<RTPSenderAudio> audio_; + const std::unique_ptr<RTPSenderVideo> video_; + + RtpPacketSender* const paced_sender_; + TransportSequenceNumberAllocator* const transport_sequence_number_allocator_; + TransportFeedbackObserver* const transport_feedback_observer_; + int64_t last_capture_time_ms_sent_; + rtc::CriticalSection send_critsect_; + + Transport* transport_; + bool sending_media_ RTC_GUARDED_BY(send_critsect_); + + size_t max_packet_size_; + + int8_t payload_type_ RTC_GUARDED_BY(send_critsect_); + std::map<int8_t, RtpUtility::Payload*> payload_type_map_; + + RtpHeaderExtensionMap rtp_header_extension_map_ + RTC_GUARDED_BY(send_critsect_); + + StreamId rtpStreamId RTC_GUARDED_BY(send_critsect_); + + StreamId mId RTC_GUARDED_BY(send_critsect_); + + // Tracks the current request for playout delay limits from application + // and decides whether the current RTP frame should include the playout + // delay extension on header. + PlayoutDelayOracle playout_delay_oracle_; + + RtpPacketHistory packet_history_; + // TODO(brandtr): Remove |flexfec_packet_history_| when the FlexfecSender + // is hooked up to the PacedSender. + RtpPacketHistory flexfec_packet_history_; + + // Statistics + rtc::CriticalSection statistics_crit_; + SendDelayMap send_delays_ RTC_GUARDED_BY(statistics_crit_); + FrameCounts frame_counts_ RTC_GUARDED_BY(statistics_crit_); + StreamDataCounters rtp_stats_ RTC_GUARDED_BY(statistics_crit_); + StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(statistics_crit_); + StreamDataCountersCallback* rtp_stats_callback_ + RTC_GUARDED_BY(statistics_crit_); + RateStatistics total_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_); + RateStatistics nack_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_); + FrameCountObserver* const frame_count_observer_; + SendSideDelayObserver* const send_side_delay_observer_; + RtcEventLog* const event_log_; + SendPacketObserver* const send_packet_observer_; + BitrateStatisticsObserver* const bitrate_callback_; + + // RTP variables + uint32_t timestamp_offset_ RTC_GUARDED_BY(send_critsect_); + uint32_t remote_ssrc_ RTC_GUARDED_BY(send_critsect_); + bool sequence_number_forced_ RTC_GUARDED_BY(send_critsect_); + uint16_t sequence_number_ RTC_GUARDED_BY(send_critsect_); + uint16_t sequence_number_rtx_ RTC_GUARDED_BY(send_critsect_); + // Must be explicitly set by the application, use of rtc::Optional + // only to keep track of correct use. + rtc::Optional<uint32_t> ssrc_ RTC_GUARDED_BY(send_critsect_); + uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(send_critsect_); + int64_t capture_time_ms_ RTC_GUARDED_BY(send_critsect_); + int64_t last_timestamp_time_ms_ RTC_GUARDED_BY(send_critsect_); + bool media_has_been_sent_ RTC_GUARDED_BY(send_critsect_); + bool last_packet_marker_bit_ RTC_GUARDED_BY(send_critsect_); + std::vector<uint32_t> csrcs_ RTC_GUARDED_BY(send_critsect_); + int rtx_ RTC_GUARDED_BY(send_critsect_); + rtc::Optional<uint32_t> ssrc_rtx_ RTC_GUARDED_BY(send_critsect_); + // Mapping rtx_payload_type_map_[associated] = rtx. + std::map<int8_t, int8_t> rtx_payload_type_map_ RTC_GUARDED_BY(send_critsect_); + size_t rtp_overhead_bytes_per_packet_ RTC_GUARDED_BY(send_critsect_); + + RateLimiter* const retransmission_rate_limiter_; + OverheadObserver* overhead_observer_; + + const bool send_side_bwe_with_overhead_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSender); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.cc new file mode 100644 index 0000000000..c61d674e07 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.cc @@ -0,0 +1,339 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_sender_audio.h" + +#include <string.h> + +#include <memory> +#include <utility> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/logging.h" +#include "rtc_base/timeutils.h" +#include "rtc_base/trace_event.h" + +namespace webrtc { + +RTPSenderAudio::RTPSenderAudio(Clock* clock, RTPSender* rtp_sender) + : clock_(clock), + rtp_sender_(rtp_sender) {} + +RTPSenderAudio::~RTPSenderAudio() {} + +int32_t RTPSenderAudio::RegisterAudioPayload( + const char payloadName[RTP_PAYLOAD_NAME_SIZE], + const int8_t payload_type, + const uint32_t frequency, + const size_t channels, + const uint32_t rate, + RtpUtility::Payload** payload) { + if (RtpUtility::StringCompare(payloadName, "cn", 2)) { + rtc::CritScope cs(&send_audio_critsect_); + // we can have multiple CNG payload types + switch (frequency) { + case 8000: + cngnb_payload_type_ = payload_type; + break; + case 16000: + cngwb_payload_type_ = payload_type; + break; + case 32000: + cngswb_payload_type_ = payload_type; + break; + case 48000: + cngfb_payload_type_ = payload_type; + break; + default: + return -1; + } + } else if (RtpUtility::StringCompare(payloadName, "telephone-event", 15)) { + rtc::CritScope cs(&send_audio_critsect_); + // Don't add it to the list + // we dont want to allow send with a DTMF payloadtype + dtmf_payload_type_ = payload_type; + dtmf_payload_freq_ = frequency; + return 0; + } + *payload = new RtpUtility::Payload( + payloadName, + PayloadUnion(AudioPayload{ + SdpAudioFormat(payloadName, frequency, channels), rate})); + return 0; +} + +bool RTPSenderAudio::MarkerBit(FrameType frame_type, int8_t payload_type) { + rtc::CritScope cs(&send_audio_critsect_); + // for audio true for first packet in a speech burst + bool marker_bit = false; + if (last_payload_type_ != payload_type) { + if (payload_type != -1 && (cngnb_payload_type_ == payload_type || + cngwb_payload_type_ == payload_type || + cngswb_payload_type_ == payload_type || + cngfb_payload_type_ == payload_type)) { + // Only set a marker bit when we change payload type to a non CNG + return false; + } + + // payload_type differ + if (last_payload_type_ == -1) { + if (frame_type != kAudioFrameCN) { + // first packet and NOT CNG + return true; + } else { + // first packet and CNG + inband_vad_active_ = true; + return false; + } + } + + // not first packet AND + // not CNG AND + // payload_type changed + + // set a marker bit when we change payload type + marker_bit = true; + } + + // For G.723 G.729, AMR etc we can have inband VAD + if (frame_type == kAudioFrameCN) { + inband_vad_active_ = true; + } else if (inband_vad_active_) { + inband_vad_active_ = false; + marker_bit = true; + } + return marker_bit; +} + +bool RTPSenderAudio::SendAudio(FrameType frame_type, + int8_t payload_type, + uint32_t rtp_timestamp, + const uint8_t* payload_data, + size_t payload_size, + const StreamId* mId) { + // From RFC 4733: + // A source has wide latitude as to how often it sends event updates. A + // natural interval is the spacing between non-event audio packets. [...] + // Alternatively, a source MAY decide to use a different spacing for event + // updates, with a value of 50 ms RECOMMENDED. + constexpr int kDtmfIntervalTimeMs = 50; + uint8_t audio_level_dbov = 0; + uint32_t dtmf_payload_freq = 0; + { + rtc::CritScope cs(&send_audio_critsect_); + audio_level_dbov = audio_level_dbov_; + dtmf_payload_freq = dtmf_payload_freq_; + } + + // Check if we have pending DTMFs to send + if (!dtmf_event_is_on_ && dtmf_queue_.PendingDtmf()) { + if ((clock_->TimeInMilliseconds() - dtmf_time_last_sent_) > + kDtmfIntervalTimeMs) { + // New tone to play + dtmf_timestamp_ = rtp_timestamp; + if (dtmf_queue_.NextDtmf(&dtmf_current_event_)) { + dtmf_event_first_packet_sent_ = false; + dtmf_length_samples_ = + dtmf_current_event_.duration_ms * (dtmf_payload_freq / 1000); + dtmf_event_is_on_ = true; + } + } + } + + // A source MAY send events and coded audio packets for the same time + // but we don't support it + if (dtmf_event_is_on_) { + if (frame_type == kEmptyFrame) { + // kEmptyFrame is used to drive the DTMF when in CN mode + // it can be triggered more frequently than we want to send the + // DTMF packets. + const unsigned int dtmf_interval_time_rtp = + dtmf_payload_freq * kDtmfIntervalTimeMs / 1000; + if ((rtp_timestamp - dtmf_timestamp_last_sent_) < + dtmf_interval_time_rtp) { + // not time to send yet + return true; + } + } + dtmf_timestamp_last_sent_ = rtp_timestamp; + uint32_t dtmf_duration_samples = rtp_timestamp - dtmf_timestamp_; + bool ended = false; + bool send = true; + + if (dtmf_length_samples_ > dtmf_duration_samples) { + if (dtmf_duration_samples <= 0) { + // Skip send packet at start, since we shouldn't use duration 0 + send = false; + } + } else { + ended = true; + dtmf_event_is_on_ = false; + dtmf_time_last_sent_ = clock_->TimeInMilliseconds(); + } + if (send) { + if (dtmf_duration_samples > 0xffff) { + // RFC 4733 2.5.2.3 Long-Duration Events + SendTelephoneEventPacket(ended, dtmf_timestamp_, + static_cast<uint16_t>(0xffff), false); + + // set new timestap for this segment + dtmf_timestamp_ = rtp_timestamp; + dtmf_duration_samples -= 0xffff; + dtmf_length_samples_ -= 0xffff; + + return SendTelephoneEventPacket(ended, dtmf_timestamp_, + static_cast<uint16_t>(dtmf_duration_samples), false); + } else { + if (!SendTelephoneEventPacket(ended, dtmf_timestamp_, + dtmf_duration_samples, + !dtmf_event_first_packet_sent_)) { + return false; + } + dtmf_event_first_packet_sent_ = true; + return true; + } + } + return true; + } + if (payload_size == 0 || payload_data == NULL) { + if (frame_type == kEmptyFrame) { + // we don't send empty audio RTP packets + // no error since we use it to drive DTMF when we use VAD + return true; + } + return false; + } + + std::unique_ptr<RtpPacketToSend> packet = rtp_sender_->AllocatePacket(); + packet->SetMarker(MarkerBit(frame_type, payload_type)); + packet->SetPayloadType(payload_type); + packet->SetTimestamp(rtp_timestamp); + packet->set_capture_time_ms(clock_->TimeInMilliseconds()); + // Update audio level extension, if included. + packet->SetExtension<AudioLevel>(frame_type == kAudioFrameSpeech, + audio_level_dbov); + + if (mId && !mId->empty()) { + packet->SetExtension<RtpMid>(*mId); + } + + uint8_t* payload = packet->AllocatePayload(payload_size); + if (!payload) // Too large payload buffer. + return false; + memcpy(payload, payload_data, payload_size); + + if (!rtp_sender_->AssignSequenceNumber(packet.get())) + return false; + + { + rtc::CritScope cs(&send_audio_critsect_); + last_payload_type_ = payload_type; + } + TRACE_EVENT_ASYNC_END2("webrtc", "Audio", rtp_timestamp, "timestamp", + packet->Timestamp(), "seqnum", + packet->SequenceNumber()); + bool send_result = rtp_sender_->SendToNetwork( + std::move(packet), kAllowRetransmission, RtpPacketSender::kHighPriority); + if (first_packet_sent_()) { + RTC_LOG(LS_INFO) << "First audio RTP packet sent to pacer"; + } + return send_result; +} + +// Audio level magnitude and voice activity flag are set for each RTP packet +int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dbov) { + if (level_dbov > 127) { + return -1; + } + rtc::CritScope cs(&send_audio_critsect_); + audio_level_dbov_ = level_dbov; + return 0; +} + +// Send a TelephoneEvent tone using RFC 2833 (4733) +int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key, + uint16_t time_ms, + uint8_t level) { + DtmfQueue::Event event; + { + rtc::CritScope lock(&send_audio_critsect_); + if (dtmf_payload_type_ < 0) { + // TelephoneEvent payloadtype not configured + return -1; + } + event.payload_type = dtmf_payload_type_; + } + event.key = key; + event.duration_ms = time_ms; + event.level = level; + return dtmf_queue_.AddDtmf(event) ? 0 : -1; +} + +bool RTPSenderAudio::SendTelephoneEventPacket(bool ended, + uint32_t dtmf_timestamp, + uint16_t duration, + bool marker_bit) { + uint8_t send_count = 1; + bool result = true; + + if (ended) { + // resend last packet in an event 3 times + send_count = 3; + } + do { + // Send DTMF data. + constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr; + constexpr size_t kDtmfSize = 4; + std::unique_ptr<RtpPacketToSend> packet( + new RtpPacketToSend(kNoExtensions, kRtpHeaderSize + kDtmfSize)); + packet->SetPayloadType(dtmf_current_event_.payload_type); + packet->SetMarker(marker_bit); + packet->SetSsrc(rtp_sender_->SSRC()); + packet->SetTimestamp(dtmf_timestamp); + packet->set_capture_time_ms(clock_->TimeInMilliseconds()); + if (!rtp_sender_->AssignSequenceNumber(packet.get())) + return false; + + // Create DTMF data. + uint8_t* dtmfbuffer = packet->AllocatePayload(kDtmfSize); + RTC_DCHECK(dtmfbuffer); + /* From RFC 2833: + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | event |E|R| volume | duration | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + // R bit always cleared + uint8_t R = 0x00; + uint8_t volume = dtmf_current_event_.level; + + // First packet un-ended + uint8_t E = ended ? 0x80 : 0x00; + + // First byte is Event number, equals key number + dtmfbuffer[0] = dtmf_current_event_.key; + dtmfbuffer[1] = E | R | volume; + ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 2, duration); + + TRACE_EVENT_INSTANT2( + TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Audio::SendTelephoneEvent", + "timestamp", packet->Timestamp(), "seqnum", packet->SequenceNumber()); + result = rtp_sender_->SendToNetwork(std::move(packet), kAllowRetransmission, + RtpPacketSender::kHighPriority); + send_count--; + } while (send_count > 0 && result); + + return result; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h new file mode 100644 index 0000000000..2fd7ceb8bb --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h @@ -0,0 +1,98 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_SENDER_AUDIO_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_SENDER_AUDIO_H_ + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/source/dtmf_queue.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "modules/rtp_rtcp/source/rtp_sender.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/onetimeevent.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class RTPSenderAudio { + public: + RTPSenderAudio(Clock* clock, RTPSender* rtp_sender); + ~RTPSenderAudio(); + + int32_t RegisterAudioPayload(const char payloadName[RTP_PAYLOAD_NAME_SIZE], + int8_t payload_type, + uint32_t frequency, + size_t channels, + uint32_t rate, + RtpUtility::Payload** payload); + + bool SendAudio(FrameType frame_type, + int8_t payload_type, + uint32_t capture_timestamp, + const uint8_t* payload_data, + size_t payload_size, + const StreamId* mId); + + // Store the audio level in dBov for + // header-extension-for-audio-level-indication. + // Valid range is [0,100]. Actual value is negative. + int32_t SetAudioLevel(uint8_t level_dbov); + + // Send a DTMF tone using RFC 2833 (4733) + int32_t SendTelephoneEvent(uint8_t key, uint16_t time_ms, uint8_t level); + + protected: + bool SendTelephoneEventPacket( + bool ended, + uint32_t dtmf_timestamp, + uint16_t duration, + bool marker_bit); // set on first packet in talk burst + + bool MarkerBit(FrameType frame_type, int8_t payload_type); + + private: + Clock* const clock_ = nullptr; + RTPSender* const rtp_sender_ = nullptr; + + rtc::CriticalSection send_audio_critsect_; + + // DTMF. + bool dtmf_event_is_on_ = false; + bool dtmf_event_first_packet_sent_ = false; + int8_t dtmf_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1; + uint32_t dtmf_payload_freq_ RTC_GUARDED_BY(send_audio_critsect_) = 8000; + uint32_t dtmf_timestamp_ = 0; + uint32_t dtmf_length_samples_ = 0; + int64_t dtmf_time_last_sent_ = 0; + uint32_t dtmf_timestamp_last_sent_ = 0; + DtmfQueue::Event dtmf_current_event_; + DtmfQueue dtmf_queue_; + + // VAD detection, used for marker bit. + bool inband_vad_active_ RTC_GUARDED_BY(send_audio_critsect_) = false; + int8_t cngnb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1; + int8_t cngwb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1; + int8_t cngswb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1; + int8_t cngfb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1; + int8_t last_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1; + + // Audio level indication. + // (https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/) + uint8_t audio_level_dbov_ RTC_GUARDED_BY(send_audio_critsect_) = 0; + OneTimeEvent first_packet_sent_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSenderAudio); +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_SENDER_AUDIO_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc new file mode 100644 index 0000000000..db760ecf7c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -0,0 +1,2005 @@ +/* + * 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 <memory> +#include <vector> + +#include "api/video/video_timing.h" +#include "logging/rtc_event_log/events/rtc_event.h" +#include "logging/rtc_event_log/mock/mock_rtc_event_log.h" +#include "modules/rtp_rtcp/include/rtp_cvo.h" +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" +#include "modules/rtp_rtcp/source/rtp_format_video_generic.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "modules/rtp_rtcp/source/rtp_sender.h" +#include "modules/rtp_rtcp/source/rtp_sender_video.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/buffer.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/rate_limiter.h" +#include "test/field_trial.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/mock_transport.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +namespace { +const int kTransmissionTimeOffsetExtensionId = 1; +const int kAbsoluteSendTimeExtensionId = 14; +const int kTransportSequenceNumberExtensionId = 13; +const int kVideoTimingExtensionId = 12; +const int kPayload = 100; +const int kRtxPayload = 98; +const uint32_t kTimestamp = 10; +const uint16_t kSeqNum = 33; +const uint32_t kSsrc = 725242; +const int kMaxPacketLength = 1500; +const uint8_t kAudioLevel = 0x5a; +const uint16_t kTransportSequenceNumber = 0xaabbu; +const uint8_t kAudioLevelExtensionId = 9; +const int kAudioPayload = 103; +const uint64_t kStartTime = 123456789; +const size_t kMaxPaddingSize = 224u; +const int kVideoRotationExtensionId = 5; +const size_t kGenericHeaderLength = 1; +const uint8_t kPayloadData[] = {47, 11, 32, 93, 89}; +const int64_t kDefaultExpectedRetransmissionTimeMs = 125; + +using ::testing::_; +using ::testing::ElementsAreArray; +using ::testing::Invoke; + +uint64_t ConvertMsToAbsSendTime(int64_t time_ms) { + return (((time_ms << 18) + 500) / 1000) & 0x00ffffff; +} + +class LoopbackTransportTest : public webrtc::Transport { + public: + LoopbackTransportTest() : total_bytes_sent_(0), last_packet_id_(-1) { + receivers_extensions_.Register(kRtpExtensionTransmissionTimeOffset, + kTransmissionTimeOffsetExtensionId); + receivers_extensions_.Register(kRtpExtensionAbsoluteSendTime, + kAbsoluteSendTimeExtensionId); + receivers_extensions_.Register(kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId); + receivers_extensions_.Register(kRtpExtensionVideoRotation, + kVideoRotationExtensionId); + receivers_extensions_.Register(kRtpExtensionAudioLevel, + kAudioLevelExtensionId); + receivers_extensions_.Register(kRtpExtensionVideoTiming, + kVideoTimingExtensionId); + } + + bool SendRtp(const uint8_t* data, + size_t len, + const PacketOptions& options) override { + last_packet_id_ = options.packet_id; + total_bytes_sent_ += len; + sent_packets_.push_back(RtpPacketReceived(&receivers_extensions_)); + EXPECT_TRUE(sent_packets_.back().Parse(data, len)); + return true; + } + bool SendRtcp(const uint8_t* data, size_t len) override { return false; } + const RtpPacketReceived& last_sent_packet() { return sent_packets_.back(); } + int packets_sent() { return sent_packets_.size(); } + + size_t total_bytes_sent_; + int last_packet_id_; + std::vector<RtpPacketReceived> sent_packets_; + + private: + RtpHeaderExtensionMap receivers_extensions_; +}; + +MATCHER_P(SameRtcEventTypeAs, value, "") { + return value == arg->GetType(); +} + +} // namespace + +class MockRtpPacketSender : public RtpPacketSender { + public: + MockRtpPacketSender() {} + virtual ~MockRtpPacketSender() {} + + MOCK_METHOD6(InsertPacket, + void(Priority priority, + uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + size_t bytes, + bool retransmission)); +}; + +class MockTransportSequenceNumberAllocator + : public TransportSequenceNumberAllocator { + public: + MOCK_METHOD0(AllocateSequenceNumber, uint16_t()); +}; + +class MockSendPacketObserver : public SendPacketObserver { + public: + MOCK_METHOD3(OnSendPacket, void(uint16_t, int64_t, uint32_t)); +}; + +class MockTransportFeedbackObserver : public TransportFeedbackObserver { + public: + MOCK_METHOD4(AddPacket, + void(uint32_t, uint16_t, size_t, const PacedPacketInfo&)); + MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&)); + MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>()); +}; + +class MockOverheadObserver : public OverheadObserver { + public: + MOCK_METHOD1(OnOverheadChanged, void(size_t overhead_bytes_per_packet)); +}; + +class RtpSenderTest : public ::testing::TestWithParam<bool> { + protected: + RtpSenderTest() + : fake_clock_(kStartTime), + mock_rtc_event_log_(), + mock_paced_sender_(), + retransmission_rate_limiter_(&fake_clock_, 1000), + rtp_sender_(), + payload_(kPayload), + transport_(), + kMarkerBit(true), + field_trials_(GetParam() ? "WebRTC-SendSideBwe-WithOverhead/Enabled/" + : "") {} + + void SetUp() override { SetUpRtpSender(true); } + + void SetUpRtpSender(bool pacer) { + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr, + nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr, + &mock_rtc_event_log_, &send_packet_observer_, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSendPayloadType(kPayload); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetTimestampOffset(0); + rtp_sender_->SetSSRC(kSsrc); + } + + SimulatedClock fake_clock_; + testing::NiceMock<MockRtcEventLog> mock_rtc_event_log_; + MockRtpPacketSender mock_paced_sender_; + testing::StrictMock<MockTransportSequenceNumberAllocator> seq_num_allocator_; + testing::StrictMock<MockSendPacketObserver> send_packet_observer_; + testing::StrictMock<MockTransportFeedbackObserver> feedback_observer_; + RateLimiter retransmission_rate_limiter_; + std::unique_ptr<RTPSender> rtp_sender_; + int payload_; + LoopbackTransportTest transport_; + const bool kMarkerBit; + test::ScopedFieldTrials field_trials_; + + void VerifyRTPHeaderCommon(const RTPHeader& rtp_header) { + VerifyRTPHeaderCommon(rtp_header, kMarkerBit, 0); + } + + void VerifyRTPHeaderCommon(const RTPHeader& rtp_header, bool marker_bit) { + VerifyRTPHeaderCommon(rtp_header, marker_bit, 0); + } + + void VerifyRTPHeaderCommon(const RTPHeader& rtp_header, + bool marker_bit, + uint8_t number_of_csrcs) { + EXPECT_EQ(marker_bit, rtp_header.markerBit); + EXPECT_EQ(payload_, rtp_header.payloadType); + EXPECT_EQ(kSeqNum, rtp_header.sequenceNumber); + EXPECT_EQ(kTimestamp, rtp_header.timestamp); + EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.ssrc); + EXPECT_EQ(number_of_csrcs, rtp_header.numCSRCs); + EXPECT_EQ(0U, rtp_header.paddingLength); + } + + std::unique_ptr<RtpPacketToSend> BuildRtpPacket(int payload_type, + bool marker_bit, + uint32_t timestamp, + int64_t capture_time_ms) { + auto packet = rtp_sender_->AllocatePacket(); + packet->SetPayloadType(payload_type); + packet->SetMarker(marker_bit); + packet->SetTimestamp(timestamp); + packet->set_capture_time_ms(capture_time_ms); + EXPECT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get())); + return packet; + } + + void SendPacket(int64_t capture_time_ms, int payload_length) { + uint32_t timestamp = capture_time_ms * 90; + auto packet = + BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms); + packet->AllocatePayload(payload_length); + + // Packet should be stored in a send bucket. + EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet), + kAllowRetransmission, + RtpPacketSender::kNormalPriority)); + } + + void SendGenericPayload() { + const uint32_t kTimestamp = 1234; + const uint8_t kPayloadType = 127; + const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds(); + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; + EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000, + 0, 1500)); + + EXPECT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData, + sizeof(kPayloadData), nullptr, nullptr, nullptr, + kDefaultExpectedRetransmissionTimeMs)); + } +}; + +// TODO(pbos): Move tests over from WithoutPacer to RtpSenderTest as this is our +// default code path. +class RtpSenderTestWithoutPacer : public RtpSenderTest { + public: + void SetUp() override { SetUpRtpSender(false); } +}; + +class TestRtpSenderVideo : public RTPSenderVideo { + public: + TestRtpSenderVideo(Clock* clock, + RTPSender* rtp_sender, + FlexfecSender* flexfec_sender) + : RTPSenderVideo(clock, rtp_sender, flexfec_sender) {} + ~TestRtpSenderVideo() override {} + + StorageType GetStorageType(const RTPVideoHeader& header, + int32_t retransmission_settings, + int64_t expected_retransmission_time_ms) { + return RTPSenderVideo::GetStorageType(GetTemporalId(header), + retransmission_settings, + expected_retransmission_time_ms); + } +}; + +class RtpSenderVideoTest : public RtpSenderTest { + protected: + void SetUp() override { + // TODO(pbos): Set up to use pacer. + SetUpRtpSender(false); + rtp_sender_video_.reset( + new TestRtpSenderVideo(&fake_clock_, rtp_sender_.get(), nullptr)); + } + std::unique_ptr<TestRtpSenderVideo> rtp_sender_video_; +}; + +TEST_P(RtpSenderTestWithoutPacer, AllocatePacketSetCsrc) { + // Configure rtp_sender with csrc. + std::vector<uint32_t> csrcs; + csrcs.push_back(0x23456789); + rtp_sender_->SetCsrcs(csrcs); + + auto packet = rtp_sender_->AllocatePacket(); + + ASSERT_TRUE(packet); + EXPECT_EQ(rtp_sender_->SSRC(), packet->Ssrc()); + EXPECT_EQ(csrcs, packet->Csrcs()); +} + +TEST_P(RtpSenderTestWithoutPacer, AllocatePacketReserveExtensions) { + // Configure rtp_sender with extensions. + ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransmissionTimeOffset, + kTransmissionTimeOffsetExtensionId)); + ASSERT_EQ( + 0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, + kAbsoluteSendTimeExtensionId)); + ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel, + kAudioLevelExtensionId)); + ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionVideoRotation, kVideoRotationExtensionId)); + + auto packet = rtp_sender_->AllocatePacket(); + + ASSERT_TRUE(packet); + // Preallocate BWE extensions RtpSender set itself. + EXPECT_TRUE(packet->HasExtension<TransmissionOffset>()); + EXPECT_TRUE(packet->HasExtension<AbsoluteSendTime>()); + EXPECT_TRUE(packet->HasExtension<TransportSequenceNumber>()); + // Do not allocate media specific extensions. + EXPECT_FALSE(packet->HasExtension<AudioLevel>()); + EXPECT_FALSE(packet->HasExtension<VideoOrientation>()); +} + +TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberAdvanceSequenceNumber) { + auto packet = rtp_sender_->AllocatePacket(); + ASSERT_TRUE(packet); + const uint16_t sequence_number = rtp_sender_->SequenceNumber(); + + EXPECT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get())); + + EXPECT_EQ(sequence_number, packet->SequenceNumber()); + EXPECT_EQ(sequence_number + 1, rtp_sender_->SequenceNumber()); +} + +TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberFailsOnNotSending) { + auto packet = rtp_sender_->AllocatePacket(); + ASSERT_TRUE(packet); + + rtp_sender_->SetSendingMediaStatus(false); + EXPECT_FALSE(rtp_sender_->AssignSequenceNumber(packet.get())); +} + +TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberMayAllowPadding) { + constexpr size_t kPaddingSize = 100; + auto packet = rtp_sender_->AllocatePacket(); + ASSERT_TRUE(packet); + + ASSERT_FALSE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo())); + packet->SetMarker(false); + ASSERT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get())); + // Packet without marker bit doesn't allow padding. + EXPECT_FALSE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo())); + + packet->SetMarker(true); + ASSERT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get())); + // Packet with marker bit allows send padding. + EXPECT_TRUE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo())); +} + +TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberSetPaddingTimestamps) { + constexpr size_t kPaddingSize = 100; + auto packet = rtp_sender_->AllocatePacket(); + ASSERT_TRUE(packet); + packet->SetMarker(true); + packet->SetTimestamp(kTimestamp); + + ASSERT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get())); + ASSERT_TRUE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo())); + + ASSERT_EQ(1u, transport_.sent_packets_.size()); + // Verify padding packet timestamp. + EXPECT_EQ(kTimestamp, transport_.last_sent_packet().Timestamp()); +} + +TEST_P(RtpSenderTestWithoutPacer, + TransportFeedbackObserverGetsCorrectByteCount) { + constexpr int kRtpOverheadBytesPerPacket = 12 + 8; + testing::NiceMock<MockOverheadObserver> mock_overhead_observer; + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_, + &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_, + nullptr, &retransmission_rate_limiter_, &mock_overhead_observer)); + rtp_sender_->SetSSRC(kSsrc); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber()) + .WillOnce(testing::Return(kTransportSequenceNumber)); + + const size_t expected_bytes = + GetParam() ? sizeof(kPayloadData) + kGenericHeaderLength + + kRtpOverheadBytesPerPacket + : sizeof(kPayloadData) + kGenericHeaderLength; + + EXPECT_CALL(feedback_observer_, + AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber, + expected_bytes, PacedPacketInfo())) + .Times(1); + EXPECT_CALL(mock_overhead_observer, + OnOverheadChanged(kRtpOverheadBytesPerPacket)) + .Times(1); + SendGenericPayload(); +} + +TEST_P(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) { + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_, + &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_, + &send_packet_observer_, &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kSsrc); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + + EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber()) + .WillOnce(testing::Return(kTransportSequenceNumber)); + EXPECT_CALL(send_packet_observer_, + OnSendPacket(kTransportSequenceNumber, _, _)) + .Times(1); + + EXPECT_CALL(feedback_observer_, + AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber, _, + PacedPacketInfo())) + .Times(1); + + SendGenericPayload(); + + const auto& packet = transport_.last_sent_packet(); + uint16_t transport_seq_no; + ASSERT_TRUE(packet.GetExtension<TransportSequenceNumber>(&transport_seq_no)); + EXPECT_EQ(kTransportSequenceNumber, transport_seq_no); + EXPECT_EQ(transport_.last_packet_id_, transport_seq_no); +} + +TEST_P(RtpSenderTestWithoutPacer, NoAllocationIfNotRegistered) { + SendGenericPayload(); +} + +TEST_P(RtpSenderTestWithoutPacer, OnSendPacketUpdated) { + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber()) + .WillOnce(testing::Return(kTransportSequenceNumber)); + EXPECT_CALL(send_packet_observer_, + OnSendPacket(kTransportSequenceNumber, _, _)) + .Times(1); + + SendGenericPayload(); +} + +TEST_P(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) { + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, + &seq_num_allocator_, &feedback_observer_, nullptr, nullptr, nullptr, + &mock_rtc_event_log_, &send_packet_observer_, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSSRC(kSsrc); + rtp_sender_->SetStorePacketsStatus(true, 10); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + + EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _)); + EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber()) + .WillOnce(testing::Return(kTransportSequenceNumber)); + EXPECT_CALL(send_packet_observer_, + OnSendPacket(kTransportSequenceNumber, _, _)) + .Times(1); + EXPECT_CALL(feedback_observer_, + AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber, _, + PacedPacketInfo())) + .Times(1); + + SendGenericPayload(); + rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, + fake_clock_.TimeInMilliseconds(), false, + PacedPacketInfo()); + + const auto& packet = transport_.last_sent_packet(); + uint16_t transport_seq_no; + EXPECT_TRUE(packet.GetExtension<TransportSequenceNumber>(&transport_seq_no)); + EXPECT_EQ(kTransportSequenceNumber, transport_seq_no); + EXPECT_EQ(transport_.last_packet_id_, transport_seq_no); +} + +TEST_P(RtpSenderTestWithoutPacer, WritesTimestampToTimingExtension) { + rtp_sender_->SetStorePacketsStatus(true, 10); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionVideoTiming, kVideoTimingExtensionId)); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + auto packet = rtp_sender_->AllocatePacket(); + packet->SetPayloadType(kPayload); + packet->SetMarker(true); + packet->SetTimestamp(kTimestamp); + packet->set_capture_time_ms(capture_time_ms); + const VideoSendTiming kVideoTiming = {0u, 0u, 0u, 0u, 0u, 0u, true}; + packet->SetExtension<VideoTimingExtension>(kVideoTiming); + EXPECT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get())); + size_t packet_size = packet->size(); + + const int kStoredTimeInMs = 100; + fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); + + EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet), + kAllowRetransmission, + RtpPacketSender::kNormalPriority)); + EXPECT_EQ(1, transport_.packets_sent()); + EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); + + VideoSendTiming video_timing; + EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>( + &video_timing)); + EXPECT_EQ(kStoredTimeInMs, video_timing.pacer_exit_delta_ms); + + fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); + rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false, + PacedPacketInfo()); + + EXPECT_EQ(2, transport_.packets_sent()); + EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); + + EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>( + &video_timing)); + EXPECT_EQ(kStoredTimeInMs * 2, video_timing.pacer_exit_delta_ms); +} + +TEST_P(RtpSenderTest, TrafficSmoothingWithExtensions) { + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority, + kSsrc, kSeqNum, _, _, _)); + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))); + + rtp_sender_->SetStorePacketsStatus(true, 10); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransmissionTimeOffset, + kTransmissionTimeOffsetExtensionId)); + EXPECT_EQ( + 0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, + kAbsoluteSendTimeExtensionId)); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + auto packet = + BuildRtpPacket(kPayload, kMarkerBit, kTimestamp, capture_time_ms); + size_t packet_size = packet->size(); + + // Packet should be stored in a send bucket. + EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet), + kAllowRetransmission, + RtpPacketSender::kNormalPriority)); + + EXPECT_EQ(0, transport_.packets_sent()); + + const int kStoredTimeInMs = 100; + fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); + + rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false, + PacedPacketInfo()); + + // Process send bucket. Packet should now be sent. + EXPECT_EQ(1, transport_.packets_sent()); + EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); + + webrtc::RTPHeader rtp_header; + transport_.last_sent_packet().GetHeader(&rtp_header); + + // Verify transmission time offset. + EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset); + uint64_t expected_send_time = + ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); + EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); +} + +TEST_P(RtpSenderTest, TrafficSmoothingRetransmits) { + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority, + kSsrc, kSeqNum, _, _, _)); + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))); + + rtp_sender_->SetStorePacketsStatus(true, 10); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransmissionTimeOffset, + kTransmissionTimeOffsetExtensionId)); + EXPECT_EQ( + 0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, + kAbsoluteSendTimeExtensionId)); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + auto packet = + BuildRtpPacket(kPayload, kMarkerBit, kTimestamp, capture_time_ms); + size_t packet_size = packet->size(); + + // Packet should be stored in a send bucket. + EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet), + kAllowRetransmission, + RtpPacketSender::kNormalPriority)); + + EXPECT_EQ(0, transport_.packets_sent()); + + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority, + kSsrc, kSeqNum, _, _, _)); + + const int kStoredTimeInMs = 100; + fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); + + EXPECT_EQ(static_cast<int>(packet_size), rtp_sender_->ReSendPacket(kSeqNum)); + EXPECT_EQ(0, transport_.packets_sent()); + + rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false, + PacedPacketInfo()); + + // Process send bucket. Packet should now be sent. + EXPECT_EQ(1, transport_.packets_sent()); + EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); + + webrtc::RTPHeader rtp_header; + transport_.last_sent_packet().GetHeader(&rtp_header); + + // Verify transmission time offset. + EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset); + uint64_t expected_send_time = + ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); + EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); +} + +// This test sends 1 regular video packet, then 4 padding packets, and then +// 1 more regular packet. +TEST_P(RtpSenderTest, SendPadding) { + // Make all (non-padding) packets go to send queue. + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority, + kSsrc, kSeqNum, _, _, _)); + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) + .Times(1 + 4 + 1); + + uint16_t seq_num = kSeqNum; + uint32_t timestamp = kTimestamp; + rtp_sender_->SetStorePacketsStatus(true, 10); + size_t rtp_header_len = kRtpHeaderSize; + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransmissionTimeOffset, + kTransmissionTimeOffsetExtensionId)); + rtp_header_len += 4; // 4 bytes extension. + EXPECT_EQ( + 0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, + kAbsoluteSendTimeExtensionId)); + rtp_header_len += 4; // 4 bytes extension. + rtp_header_len += 4; // 4 extra bytes common to all extension headers. + + webrtc::RTPHeader rtp_header; + + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + auto packet = + BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms); + const uint32_t media_packet_timestamp = timestamp; + size_t packet_size = packet->size(); + + // Packet should be stored in a send bucket. + EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet), + kAllowRetransmission, + RtpPacketSender::kNormalPriority)); + + int total_packets_sent = 0; + EXPECT_EQ(total_packets_sent, transport_.packets_sent()); + + const int kStoredTimeInMs = 100; + fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); + rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false, + PacedPacketInfo()); + // Packet should now be sent. This test doesn't verify the regular video + // packet, since it is tested in another test. + EXPECT_EQ(++total_packets_sent, transport_.packets_sent()); + timestamp += 90 * kStoredTimeInMs; + + // Send padding 4 times, waiting 50 ms between each. + for (int i = 0; i < 4; ++i) { + const int kPaddingPeriodMs = 50; + const size_t kPaddingBytes = 100; + const size_t kMaxPaddingLength = 224; // Value taken from rtp_sender.cc. + // Padding will be forced to full packets. + EXPECT_EQ(kMaxPaddingLength, + rtp_sender_->TimeToSendPadding(kPaddingBytes, PacedPacketInfo())); + + // Process send bucket. Padding should now be sent. + EXPECT_EQ(++total_packets_sent, transport_.packets_sent()); + EXPECT_EQ(kMaxPaddingLength + rtp_header_len, + transport_.last_sent_packet().size()); + + transport_.last_sent_packet().GetHeader(&rtp_header); + EXPECT_EQ(kMaxPaddingLength, rtp_header.paddingLength); + + // Verify sequence number and timestamp. The timestamp should be the same + // as the last media packet. + EXPECT_EQ(seq_num++, rtp_header.sequenceNumber); + EXPECT_EQ(media_packet_timestamp, rtp_header.timestamp); + // Verify transmission time offset. + int offset = timestamp - media_packet_timestamp; + EXPECT_EQ(offset, rtp_header.extension.transmissionTimeOffset); + uint64_t expected_send_time = + ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); + EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); + fake_clock_.AdvanceTimeMilliseconds(kPaddingPeriodMs); + timestamp += 90 * kPaddingPeriodMs; + } + + // Send a regular video packet again. + capture_time_ms = fake_clock_.TimeInMilliseconds(); + packet = BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms); + packet_size = packet->size(); + + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority, + kSsrc, seq_num, _, _, _)); + + // Packet should be stored in a send bucket. + EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet), + kAllowRetransmission, + RtpPacketSender::kNormalPriority)); + + rtp_sender_->TimeToSendPacket(kSsrc, seq_num, capture_time_ms, false, + PacedPacketInfo()); + // Process send bucket. + EXPECT_EQ(++total_packets_sent, transport_.packets_sent()); + EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); + transport_.last_sent_packet().GetHeader(&rtp_header); + + // Verify sequence number and timestamp. + EXPECT_EQ(seq_num, rtp_header.sequenceNumber); + EXPECT_EQ(timestamp, rtp_header.timestamp); + // Verify transmission time offset. This packet is sent without delay. + EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset); + uint64_t expected_send_time = + ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); + EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); +} + +TEST_P(RtpSenderTest, OnSendPacketUpdated) { + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + rtp_sender_->SetStorePacketsStatus(true, 10); + + EXPECT_CALL(send_packet_observer_, + OnSendPacket(kTransportSequenceNumber, _, _)) + .Times(1); + EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber()) + .WillOnce(testing::Return(kTransportSequenceNumber)); + EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _)) + .Times(1); + + SendGenericPayload(); // Packet passed to pacer. + const bool kIsRetransmit = false; + rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, + fake_clock_.TimeInMilliseconds(), kIsRetransmit, + PacedPacketInfo()); + EXPECT_EQ(1, transport_.packets_sent()); +} + +TEST_P(RtpSenderTest, OnSendPacketNotUpdatedForRetransmits) { + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + rtp_sender_->SetStorePacketsStatus(true, 10); + + EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0); + EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber()) + .WillOnce(testing::Return(kTransportSequenceNumber)); + EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _)) + .Times(1); + + SendGenericPayload(); // Packet passed to pacer. + const bool kIsRetransmit = true; + rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, + fake_clock_.TimeInMilliseconds(), kIsRetransmit, + PacedPacketInfo()); + EXPECT_EQ(1, transport_.packets_sent()); +} + +TEST_P(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) { + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, + nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr, + nullptr, nullptr, &send_packet_observer_, &retransmission_rate_limiter_, + nullptr)); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSSRC(kSsrc); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionTransportSequenceNumber, + kTransportSequenceNumberExtensionId)); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetStorePacketsStatus(true, 10); + + EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0); + EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _)) + .Times(1); + + SendGenericPayload(); // Packet passed to pacer. + const bool kIsRetransmit = false; + rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, + fake_clock_.TimeInMilliseconds(), kIsRetransmit, + PacedPacketInfo()); + EXPECT_EQ(1, transport_.packets_sent()); +} + +TEST_P(RtpSenderTest, SendRedundantPayloads) { + MockTransport transport; + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSSRC(kSsrc); + rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload); + + uint16_t seq_num = kSeqNum; + rtp_sender_->SetStorePacketsStatus(true, 10); + int32_t rtp_header_len = kRtpHeaderSize; + EXPECT_EQ( + 0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, + kAbsoluteSendTimeExtensionId)); + rtp_header_len += 4; // 4 bytes extension. + rtp_header_len += 4; // 4 extra bytes common to all extension headers. + + rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); + rtp_sender_->SetRtxSsrc(1234); + + const size_t kNumPayloadSizes = 10; + const size_t kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700, + 750, 800, 850, 900, 950}; + // Expect all packets go through the pacer. + EXPECT_CALL(mock_paced_sender_, + InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _)) + .Times(kNumPayloadSizes); + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) + .Times(kNumPayloadSizes); + + // Send 10 packets of increasing size. + for (size_t i = 0; i < kNumPayloadSizes; ++i) { + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + EXPECT_CALL(transport, SendRtp(_, _, _)).WillOnce(testing::Return(true)); + SendPacket(capture_time_ms, kPayloadSizes[i]); + rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false, + PacedPacketInfo()); + fake_clock_.AdvanceTimeMilliseconds(33); + } + + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) + .Times(::testing::AtLeast(4)); + + // The amount of padding to send it too small to send a payload packet. + EXPECT_CALL(transport, SendRtp(_, kMaxPaddingSize + rtp_header_len, _)) + .WillOnce(testing::Return(true)); + EXPECT_EQ(kMaxPaddingSize, + rtp_sender_->TimeToSendPadding(49, PacedPacketInfo())); + + EXPECT_CALL(transport, + SendRtp(_, kPayloadSizes[0] + rtp_header_len + kRtxHeaderSize, _)) + .WillOnce(testing::Return(true)); + EXPECT_EQ(kPayloadSizes[0], + rtp_sender_->TimeToSendPadding(500, PacedPacketInfo())); + + EXPECT_CALL(transport, SendRtp(_, kPayloadSizes[kNumPayloadSizes - 1] + + rtp_header_len + kRtxHeaderSize, + _)) + .WillOnce(testing::Return(true)); + EXPECT_CALL(transport, SendRtp(_, kMaxPaddingSize + rtp_header_len, _)) + .WillOnce(testing::Return(true)); + EXPECT_EQ(kPayloadSizes[kNumPayloadSizes - 1] + kMaxPaddingSize, + rtp_sender_->TimeToSendPadding(999, PacedPacketInfo())); +} + +TEST_P(RtpSenderTestWithoutPacer, SendGenericVideo) { + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + + // Send keyframe + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + auto sent_payload = transport_.last_sent_packet().payload(); + uint8_t generic_header = sent_payload[0]; + EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit); + EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit); + EXPECT_THAT(sent_payload.subview(1), ElementsAreArray(payload)); + + // Send delta frame + payload[0] = 13; + payload[1] = 42; + payload[4] = 13; + + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + sent_payload = transport_.last_sent_packet().payload(); + generic_header = sent_payload[0]; + EXPECT_FALSE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit); + EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit); + EXPECT_THAT(sent_payload.subview(1), ElementsAreArray(payload)); +} + +TEST_P(RtpSenderTest, SendFlexfecPackets) { + constexpr int kMediaPayloadType = 127; + constexpr int kFlexfecPayloadType = 118; + constexpr uint32_t kMediaSsrc = 1234; + constexpr uint32_t kFlexfecSsrc = 5678; + const std::vector<RtpExtension> kNoRtpExtensions; + const std::vector<RtpExtensionSize> kNoRtpExtensionSizes; + FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpExtensions, kNoRtpExtensionSizes, + nullptr /* rtp_state */, &fake_clock_); + + // Reset |rtp_sender_| to use FlexFEC. + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender, + &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr, + &mock_rtc_event_log_, &send_packet_observer_, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kMediaSsrc); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSendPayloadType(kMediaPayloadType); + rtp_sender_->SetStorePacketsStatus(true, 10); + + // Parameters selected to generate a single FEC packet per media packet. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + rtp_sender_->SetFecParameters(params, params); + + EXPECT_CALL(mock_paced_sender_, + InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum, + _, _, false)); + uint16_t flexfec_seq_num; + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority, + kFlexfecSsrc, _, _, _, false)) + .WillOnce(testing::SaveArg<2>(&flexfec_seq_num)); + SendGenericPayload(); + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) + .Times(2); + EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kMediaSsrc, kSeqNum, + fake_clock_.TimeInMilliseconds(), + false, PacedPacketInfo())); + EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kFlexfecSsrc, flexfec_seq_num, + fake_clock_.TimeInMilliseconds(), + false, PacedPacketInfo())); + ASSERT_EQ(2, transport_.packets_sent()); + const RtpPacketReceived& media_packet = transport_.sent_packets_[0]; + EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType()); + EXPECT_EQ(kSeqNum, media_packet.SequenceNumber()); + EXPECT_EQ(kMediaSsrc, media_packet.Ssrc()); + const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[1]; + EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType()); + EXPECT_EQ(flexfec_seq_num, flexfec_packet.SequenceNumber()); + EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc()); +} + +// TODO(ilnik): because of webrtc:7859. Once FEC moved below pacer, this test +// should be removed. +TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) { + constexpr int kMediaPayloadType = 127; + constexpr int kFlexfecPayloadType = 118; + constexpr uint32_t kMediaSsrc = 1234; + constexpr uint32_t kFlexfecSsrc = 5678; + const std::vector<RtpExtension> kNoRtpExtensions; + const std::vector<RtpExtensionSize> kNoRtpExtensionSizes; + + FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpExtensions, kNoRtpExtensionSizes, + nullptr /* rtp_state */, &fake_clock_); + + // Reset |rtp_sender_| to use FlexFEC. + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender, + &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr, + &mock_rtc_event_log_, &send_packet_observer_, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kMediaSsrc); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSendPayloadType(kMediaPayloadType); + rtp_sender_->SetStorePacketsStatus(true, 10); + + // Need extension to be registered for timing frames to be sent. + ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionVideoTiming, kVideoTimingExtensionId)); + + // Parameters selected to generate a single FEC packet per media packet. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + rtp_sender_->SetFecParameters(params, params); + + EXPECT_CALL(mock_paced_sender_, + InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum, + _, _, false)); + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority, + kFlexfecSsrc, _, _, _, false)) + .Times(0); // Not called because packet should not be protected. + + const uint32_t kTimestamp = 1234; + const uint8_t kPayloadType = 127; + const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds(); + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; + EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000, + 0, 1500)); + RTPVideoHeader video_header; + memset(&video_header, 0, sizeof(RTPVideoHeader)); + video_header.video_timing.flags = TimingFrameFlags::kTriggeredByTimer; + EXPECT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData, + sizeof(kPayloadData), nullptr, &video_header, nullptr, + kDefaultExpectedRetransmissionTimeMs)); + + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) + .Times(1); + EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kMediaSsrc, kSeqNum, + fake_clock_.TimeInMilliseconds(), + false, PacedPacketInfo())); + ASSERT_EQ(1, transport_.packets_sent()); + const RtpPacketReceived& media_packet = transport_.sent_packets_[0]; + EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType()); + EXPECT_EQ(kSeqNum, media_packet.SequenceNumber()); + EXPECT_EQ(kMediaSsrc, media_packet.Ssrc()); + + // Now try to send not a timing frame. + uint16_t flexfec_seq_num; + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority, + kFlexfecSsrc, _, _, _, false)) + .WillOnce(testing::SaveArg<2>(&flexfec_seq_num)); + EXPECT_CALL(mock_paced_sender_, + InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, + kSeqNum + 1, _, _, false)); + video_header.video_timing.flags = TimingFrameFlags::kInvalid; + EXPECT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, kPayloadType, kTimestamp + 1, kCaptureTimeMs + 1, + kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr, + kDefaultExpectedRetransmissionTimeMs)); + + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) + .Times(2); + EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kMediaSsrc, kSeqNum + 1, + fake_clock_.TimeInMilliseconds(), + false, PacedPacketInfo())); + EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kFlexfecSsrc, flexfec_seq_num, + fake_clock_.TimeInMilliseconds(), + false, PacedPacketInfo())); + ASSERT_EQ(3, transport_.packets_sent()); + const RtpPacketReceived& media_packet2 = transport_.sent_packets_[1]; + EXPECT_EQ(kMediaPayloadType, media_packet2.PayloadType()); + EXPECT_EQ(kSeqNum + 1, media_packet2.SequenceNumber()); + EXPECT_EQ(kMediaSsrc, media_packet2.Ssrc()); + const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[2]; + EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType()); + EXPECT_EQ(flexfec_seq_num, flexfec_packet.SequenceNumber()); + EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc()); +} + +TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) { + constexpr int kMediaPayloadType = 127; + constexpr int kFlexfecPayloadType = 118; + constexpr uint32_t kMediaSsrc = 1234; + constexpr uint32_t kFlexfecSsrc = 5678; + const std::vector<RtpExtension> kNoRtpExtensions; + const std::vector<RtpExtensionSize> kNoRtpExtensionSizes; + FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpExtensions, kNoRtpExtensionSizes, + nullptr /* rtp_state */, &fake_clock_); + + // Reset |rtp_sender_| to use FlexFEC. + rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr, + &flexfec_sender, &seq_num_allocator_, nullptr, + nullptr, nullptr, nullptr, + &mock_rtc_event_log_, &send_packet_observer_, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kMediaSsrc); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSendPayloadType(kMediaPayloadType); + + // Parameters selected to generate a single FEC packet per media packet. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + rtp_sender_->SetFecParameters(params, params); + + EXPECT_CALL(mock_rtc_event_log_, + LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) + .Times(2); + SendGenericPayload(); + ASSERT_EQ(2, transport_.packets_sent()); + const RtpPacketReceived& media_packet = transport_.sent_packets_[0]; + EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType()); + EXPECT_EQ(kMediaSsrc, media_packet.Ssrc()); + const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[1]; + EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType()); + EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc()); +} + +TEST_P(RtpSenderTest, FecOverheadRate) { + constexpr int kMediaPayloadType = 127; + constexpr int kFlexfecPayloadType = 118; + constexpr uint32_t kMediaSsrc = 1234; + constexpr uint32_t kFlexfecSsrc = 5678; + const std::vector<RtpExtension> kNoRtpExtensions; + const std::vector<RtpExtensionSize> kNoRtpExtensionSizes; + FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpExtensions, kNoRtpExtensionSizes, + nullptr /* rtp_state */, &fake_clock_); + + // Reset |rtp_sender_| to use FlexFEC. + rtp_sender_.reset(new RTPSender( + false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender, + &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr, + &mock_rtc_event_log_, &send_packet_observer_, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kMediaSsrc); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSendPayloadType(kMediaPayloadType); + + // Parameters selected to generate a single FEC packet per media packet. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + rtp_sender_->SetFecParameters(params, params); + + constexpr size_t kNumMediaPackets = 10; + constexpr size_t kNumFecPackets = kNumMediaPackets; + constexpr int64_t kTimeBetweenPacketsMs = 10; + EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, false)) + .Times(kNumMediaPackets + kNumFecPackets); + for (size_t i = 0; i < kNumMediaPackets; ++i) { + SendGenericPayload(); + fake_clock_.AdvanceTimeMilliseconds(kTimeBetweenPacketsMs); + } + constexpr size_t kRtpHeaderLength = 12; + constexpr size_t kFlexfecHeaderLength = 20; + constexpr size_t kGenericCodecHeaderLength = 1; + constexpr size_t kPayloadLength = sizeof(kPayloadData); + constexpr size_t kPacketLength = kRtpHeaderLength + kFlexfecHeaderLength + + kGenericCodecHeaderLength + kPayloadLength; + EXPECT_NEAR(kNumFecPackets * kPacketLength * 8 / + (kNumFecPackets * kTimeBetweenPacketsMs / 1000.0f), + rtp_sender_->FecOverheadRate(), 500); +} + +TEST_P(RtpSenderTest, FrameCountCallbacks) { + class TestCallback : public FrameCountObserver { + public: + TestCallback() : FrameCountObserver(), num_calls_(0), ssrc_(0) {} + virtual ~TestCallback() {} + + void FrameCountUpdated(const FrameCounts& frame_counts, + uint32_t ssrc) override { + ++num_calls_; + ssrc_ = ssrc; + frame_counts_ = frame_counts; + } + + uint32_t num_calls_; + uint32_t ssrc_; + FrameCounts frame_counts_; + } callback; + + rtp_sender_.reset( + new RTPSender(false, &fake_clock_, &transport_, &mock_paced_sender_, + nullptr, nullptr, nullptr, nullptr, &callback, nullptr, + nullptr, nullptr, &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kSsrc); + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + rtp_sender_->SetStorePacketsStatus(true, 1); + uint32_t ssrc = rtp_sender_->SSRC(); + + EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, _)) + .Times(::testing::AtLeast(2)); + + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + EXPECT_EQ(1U, callback.num_calls_); + EXPECT_EQ(ssrc, callback.ssrc_); + EXPECT_EQ(1, callback.frame_counts_.key_frames); + EXPECT_EQ(0, callback.frame_counts_.delta_frames); + + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + EXPECT_EQ(2U, callback.num_calls_); + EXPECT_EQ(ssrc, callback.ssrc_); + EXPECT_EQ(1, callback.frame_counts_.key_frames); + EXPECT_EQ(1, callback.frame_counts_.delta_frames); + + rtp_sender_.reset(); +} + +TEST_P(RtpSenderTest, BitrateCallbacks) { + class TestCallback : public BitrateStatisticsObserver { + public: + TestCallback() + : BitrateStatisticsObserver(), + num_calls_(0), + ssrc_(0), + total_bitrate_(0), + retransmit_bitrate_(0) {} + virtual ~TestCallback() {} + + void Notify(uint32_t total_bitrate, + uint32_t retransmit_bitrate, + uint32_t ssrc) override { + ++num_calls_; + ssrc_ = ssrc; + total_bitrate_ = total_bitrate; + retransmit_bitrate_ = retransmit_bitrate; + } + + uint32_t num_calls_; + uint32_t ssrc_; + uint32_t total_bitrate_; + uint32_t retransmit_bitrate_; + } callback; + rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr, + nullptr, nullptr, nullptr, &callback, nullptr, + nullptr, nullptr, nullptr, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kSsrc); + + // Simulate kNumPackets sent with kPacketInterval ms intervals, with the + // number of packets selected so that we fill (but don't overflow) the one + // second averaging window. + const uint32_t kWindowSizeMs = 1000; + const uint32_t kPacketInterval = 20; + const uint32_t kNumPackets = + (kWindowSizeMs - kPacketInterval) / kPacketInterval; + // Overhead = 12 bytes RTP header + 1 byte generic header. + const uint32_t kPacketOverhead = 13; + + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + rtp_sender_->SetStorePacketsStatus(true, 1); + uint32_t ssrc = rtp_sender_->SSRC(); + + // Initial process call so we get a new time window. + rtp_sender_->ProcessBitrate(); + + // Send a few frames. + for (uint32_t i = 0; i < kNumPackets; ++i) { + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + fake_clock_.AdvanceTimeMilliseconds(kPacketInterval); + } + + rtp_sender_->ProcessBitrate(); + + // We get one call for every stats updated, thus two calls since both the + // stream stats and the retransmit stats are updated once. + EXPECT_EQ(2u, callback.num_calls_); + EXPECT_EQ(ssrc, callback.ssrc_); + const uint32_t kTotalPacketSize = kPacketOverhead + sizeof(payload); + // Bitrate measured over delta between last and first timestamp, plus one. + const uint32_t kExpectedWindowMs = kNumPackets * kPacketInterval + 1; + const uint32_t kExpectedBitsAccumulated = kTotalPacketSize * kNumPackets * 8; + const uint32_t kExpectedRateBps = + (kExpectedBitsAccumulated * 1000 + (kExpectedWindowMs / 2)) / + kExpectedWindowMs; + EXPECT_EQ(kExpectedRateBps, callback.total_bitrate_); + + rtp_sender_.reset(); +} + +class RtpSenderAudioTest : public RtpSenderTest { + protected: + RtpSenderAudioTest() {} + + void SetUp() override { + payload_ = kAudioPayload; + rtp_sender_.reset(new RTPSender(true, &fake_clock_, &transport_, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSSRC(kSsrc); + rtp_sender_->SetSequenceNumber(kSeqNum); + } +}; + +TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacks) { + class TestCallback : public StreamDataCountersCallback { + public: + TestCallback() : StreamDataCountersCallback(), ssrc_(0), counters_() {} + virtual ~TestCallback() {} + + void DataCountersUpdated(const StreamDataCounters& counters, + uint32_t ssrc) override { + ssrc_ = ssrc; + counters_ = counters; + } + + uint32_t ssrc_; + StreamDataCounters counters_; + + void MatchPacketCounter(const RtpPacketCounter& expected, + const RtpPacketCounter& actual) { + EXPECT_EQ(expected.payload_bytes, actual.payload_bytes); + EXPECT_EQ(expected.header_bytes, actual.header_bytes); + EXPECT_EQ(expected.padding_bytes, actual.padding_bytes); + EXPECT_EQ(expected.packets, actual.packets); + } + + void Matches(uint32_t ssrc, const StreamDataCounters& counters) { + EXPECT_EQ(ssrc, ssrc_); + MatchPacketCounter(counters.transmitted, counters_.transmitted); + MatchPacketCounter(counters.retransmitted, counters_.retransmitted); + EXPECT_EQ(counters.fec.packets, counters_.fec.packets); + } + } callback; + + const uint8_t kRedPayloadType = 96; + const uint8_t kUlpfecPayloadType = 97; + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + rtp_sender_->SetStorePacketsStatus(true, 1); + uint32_t ssrc = rtp_sender_->SSRC(); + + rtp_sender_->RegisterRtpStatisticsCallback(&callback); + + // Send a frame. + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + StreamDataCounters expected; + expected.transmitted.payload_bytes = 6; + expected.transmitted.header_bytes = 12; + expected.transmitted.padding_bytes = 0; + expected.transmitted.packets = 1; + expected.retransmitted.payload_bytes = 0; + expected.retransmitted.header_bytes = 0; + expected.retransmitted.padding_bytes = 0; + expected.retransmitted.packets = 0; + expected.fec.packets = 0; + callback.Matches(ssrc, expected); + + // Retransmit a frame. + uint16_t seqno = rtp_sender_->SequenceNumber() - 1; + rtp_sender_->ReSendPacket(seqno, 0); + expected.transmitted.payload_bytes = 12; + expected.transmitted.header_bytes = 24; + expected.transmitted.packets = 2; + expected.retransmitted.payload_bytes = 6; + expected.retransmitted.header_bytes = 12; + expected.retransmitted.padding_bytes = 0; + expected.retransmitted.packets = 1; + callback.Matches(ssrc, expected); + + // Send padding. + rtp_sender_->TimeToSendPadding(kMaxPaddingSize, PacedPacketInfo()); + expected.transmitted.payload_bytes = 12; + expected.transmitted.header_bytes = 36; + expected.transmitted.padding_bytes = kMaxPaddingSize; + expected.transmitted.packets = 3; + callback.Matches(ssrc, expected); + + // Send ULPFEC. + rtp_sender_->SetUlpfecConfig(kRedPayloadType, kUlpfecPayloadType); + FecProtectionParams fec_params; + fec_params.fec_mask_type = kFecMaskRandom; + fec_params.fec_rate = 1; + fec_params.max_fec_frames = 1; + rtp_sender_->SetFecParameters(fec_params, fec_params); + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + expected.transmitted.payload_bytes = 40; + expected.transmitted.header_bytes = 60; + expected.transmitted.packets = 5; + expected.fec.packets = 1; + callback.Matches(ssrc, expected); + + rtp_sender_->RegisterRtpStatisticsCallback(nullptr); +} + +TEST_P(RtpSenderAudioTest, SendAudio) { + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + auto sent_payload = transport_.last_sent_packet().payload(); + EXPECT_THAT(sent_payload, ElementsAreArray(payload)); +} + +TEST_P(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) { + EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel)); + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel, + kAudioLevelExtensionId)); + + char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME"; + const uint8_t payload_type = 127; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + auto sent_payload = transport_.last_sent_packet().payload(); + EXPECT_THAT(sent_payload, ElementsAreArray(payload)); + // Verify AudioLevel extension. + bool voice_activity; + uint8_t audio_level; + EXPECT_TRUE(transport_.last_sent_packet().GetExtension<AudioLevel>( + &voice_activity, &audio_level)); + EXPECT_EQ(kAudioLevel, audio_level); + EXPECT_FALSE(voice_activity); +} + +// As RFC4733, named telephone events are carried as part of the audio stream +// and must use the same sequence number and timestamp base as the regular +// audio channel. +// This test checks the marker bit for the first packet and the consequent +// packets of the same telephone event. Since it is specifically for DTMF +// events, ignoring audio packets and sending kEmptyFrame instead of those. +TEST_P(RtpSenderAudioTest, CheckMarkerBitForTelephoneEvents) { + const char* kDtmfPayloadName = "telephone-event"; + const uint32_t kPayloadFrequency = 8000; + const uint8_t kPayloadType = 126; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(kDtmfPayloadName, kPayloadType, + kPayloadFrequency, 0, 0)); + // For Telephone events, payload is not added to the registered payload list, + // it will register only the payload used for audio stream. + // Registering the payload again for audio stream with different payload name. + const char* kPayloadName = "payload_name"; + ASSERT_EQ(0, rtp_sender_->RegisterPayload(kPayloadName, kPayloadType, + kPayloadFrequency, 1, 0)); + int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); + // DTMF event key=9, duration=500 and attenuationdB=10 + rtp_sender_->SendTelephoneEvent(9, 500, 10); + // During start, it takes the starting timestamp as last sent timestamp. + // The duration is calculated as the difference of current and last sent + // timestamp. So for first call it will skip since the duration is zero. + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kEmptyFrame, kPayloadType, capture_time_ms, 0, nullptr, 0, nullptr, + nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + // DTMF Sample Length is (Frequency/1000) * Duration. + // So in this case, it is (8000/1000) * 500 = 4000. + // Sending it as two packets. + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kEmptyFrame, kPayloadType, capture_time_ms + 2000, 0, nullptr, 0, nullptr, + nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + // Marker Bit should be set to 1 for first packet. + EXPECT_TRUE(transport_.last_sent_packet().Marker()); + + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kEmptyFrame, kPayloadType, capture_time_ms + 4000, 0, nullptr, 0, nullptr, + nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + // Marker Bit should be set to 0 for rest of the packets. + EXPECT_FALSE(transport_.last_sent_packet().Marker()); +} + +TEST_P(RtpSenderTestWithoutPacer, BytesReportedCorrectly) { + const char* kPayloadName = "GENERIC"; + const uint8_t kPayloadType = 127; + rtp_sender_->SetSSRC(1234); + rtp_sender_->SetRtxSsrc(4321); + rtp_sender_->SetRtxPayloadType(kPayloadType - 1, kPayloadType); + rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); + + ASSERT_EQ(0, rtp_sender_->RegisterPayload(kPayloadName, kPayloadType, 90000, + 0, 1500)); + uint8_t payload[] = {47, 11, 32, 93, 89}; + + ASSERT_TRUE(rtp_sender_->SendOutgoingData( + kVideoFrameKey, kPayloadType, 1234, 4321, payload, sizeof(payload), + nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); + + // Will send 2 full-size padding packets. + rtp_sender_->TimeToSendPadding(1, PacedPacketInfo()); + rtp_sender_->TimeToSendPadding(1, PacedPacketInfo()); + + StreamDataCounters rtp_stats; + StreamDataCounters rtx_stats; + rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats); + + // Payload + 1-byte generic header. + EXPECT_GT(rtp_stats.first_packet_time_ms, -1); + EXPECT_EQ(rtp_stats.transmitted.payload_bytes, sizeof(payload) + 1); + EXPECT_EQ(rtp_stats.transmitted.header_bytes, 12u); + EXPECT_EQ(rtp_stats.transmitted.padding_bytes, 0u); + EXPECT_EQ(rtx_stats.transmitted.payload_bytes, 0u); + EXPECT_EQ(rtx_stats.transmitted.header_bytes, 24u); + EXPECT_EQ(rtx_stats.transmitted.padding_bytes, 2 * kMaxPaddingSize); + + EXPECT_EQ(rtp_stats.transmitted.TotalBytes(), + rtp_stats.transmitted.payload_bytes + + rtp_stats.transmitted.header_bytes + + rtp_stats.transmitted.padding_bytes); + EXPECT_EQ(rtx_stats.transmitted.TotalBytes(), + rtx_stats.transmitted.payload_bytes + + rtx_stats.transmitted.header_bytes + + rtx_stats.transmitted.padding_bytes); + + EXPECT_EQ( + transport_.total_bytes_sent_, + rtp_stats.transmitted.TotalBytes() + rtx_stats.transmitted.TotalBytes()); +} + +TEST_P(RtpSenderTestWithoutPacer, RespectsNackBitrateLimit) { + const int32_t kPacketSize = 1400; + const int32_t kNumPackets = 30; + + retransmission_rate_limiter_.SetMaxRate(kPacketSize * kNumPackets * 8); + + rtp_sender_->SetStorePacketsStatus(true, kNumPackets); + const uint16_t kStartSequenceNumber = rtp_sender_->SequenceNumber(); + std::vector<uint16_t> sequence_numbers; + for (int32_t i = 0; i < kNumPackets; ++i) { + sequence_numbers.push_back(kStartSequenceNumber + i); + fake_clock_.AdvanceTimeMilliseconds(1); + SendPacket(fake_clock_.TimeInMilliseconds(), kPacketSize); + } + EXPECT_EQ(kNumPackets, transport_.packets_sent()); + + fake_clock_.AdvanceTimeMilliseconds(1000 - kNumPackets); + + // Resending should work - brings the bandwidth up to the limit. + // NACK bitrate is capped to the same bitrate as the encoder, since the max + // protection overhead is 50% (see MediaOptimization::SetTargetRates). + rtp_sender_->OnReceivedNack(sequence_numbers, 0); + EXPECT_EQ(kNumPackets * 2, transport_.packets_sent()); + + // Must be at least 5ms in between retransmission attempts. + fake_clock_.AdvanceTimeMilliseconds(5); + + // Resending should not work, bandwidth exceeded. + rtp_sender_->OnReceivedNack(sequence_numbers, 0); + EXPECT_EQ(kNumPackets * 2, transport_.packets_sent()); +} + +TEST_P(RtpSenderVideoTest, KeyFrameHasCVO) { + uint8_t kFrame[kMaxPacketLength]; + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionVideoRotation, kVideoRotationExtensionId)); + + RTPVideoHeader hdr = {0}; + hdr.rotation = kVideoRotation_0; + rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload, + kTimestamp, 0, kFrame, sizeof(kFrame), nullptr, + &hdr, kDefaultExpectedRetransmissionTimeMs); + + VideoRotation rotation; + EXPECT_TRUE( + transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation)); + EXPECT_EQ(kVideoRotation_0, rotation); +} + +TEST_P(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) { + uint8_t kFrame[kMaxPacketLength]; + const int64_t kPacketizationTimeMs = 100; + const int64_t kEncodeStartDeltaMs = 10; + const int64_t kEncodeFinishDeltaMs = 50; + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionVideoTiming, kVideoTimingExtensionId)); + + const int64_t kCaptureTimestamp = fake_clock_.TimeInMilliseconds(); + + RTPVideoHeader hdr = {0}; + hdr.video_timing.flags = TimingFrameFlags::kTriggeredByTimer; + hdr.video_timing.encode_start_delta_ms = kEncodeStartDeltaMs; + hdr.video_timing.encode_finish_delta_ms = kEncodeFinishDeltaMs; + + fake_clock_.AdvanceTimeMilliseconds(kPacketizationTimeMs); + rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload, + kTimestamp, kCaptureTimestamp, kFrame, + sizeof(kFrame), nullptr, &hdr, + kDefaultExpectedRetransmissionTimeMs); + VideoSendTiming timing; + EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>( + &timing)); + EXPECT_EQ(kPacketizationTimeMs, timing.packetization_finish_delta_ms); + EXPECT_EQ(kEncodeStartDeltaMs, timing.encode_start_delta_ms); + EXPECT_EQ(kEncodeFinishDeltaMs, timing.encode_finish_delta_ms); +} + +TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) { + uint8_t kFrame[kMaxPacketLength]; + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionVideoRotation, kVideoRotationExtensionId)); + + RTPVideoHeader hdr = {0}; + hdr.rotation = kVideoRotation_90; + EXPECT_TRUE(rtp_sender_video_->SendVideo( + kRtpVideoGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, + sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); + + hdr.rotation = kVideoRotation_0; + EXPECT_TRUE(rtp_sender_video_->SendVideo( + kRtpVideoGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, + sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); + + VideoRotation rotation; + EXPECT_TRUE( + transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation)); + EXPECT_EQ(kVideoRotation_0, rotation); +} + +TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenNonZero) { + uint8_t kFrame[kMaxPacketLength]; + EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( + kRtpExtensionVideoRotation, kVideoRotationExtensionId)); + + RTPVideoHeader hdr = {0}; + hdr.rotation = kVideoRotation_90; + EXPECT_TRUE(rtp_sender_video_->SendVideo( + kRtpVideoGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, + sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); + + EXPECT_TRUE(rtp_sender_video_->SendVideo( + kRtpVideoGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, + sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); + + VideoRotation rotation; + EXPECT_TRUE( + transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation)); + EXPECT_EQ(kVideoRotation_90, rotation); +} + +// Make sure rotation is parsed correctly when the Camera (C) and Flip (F) bits +// are set in the CVO byte. +TEST_P(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) { + // Test extracting rotation when Camera (C) and Flip (F) bits are zero. + EXPECT_EQ(kVideoRotation_0, ConvertCVOByteToVideoRotation(0)); + EXPECT_EQ(kVideoRotation_90, ConvertCVOByteToVideoRotation(1)); + EXPECT_EQ(kVideoRotation_180, ConvertCVOByteToVideoRotation(2)); + EXPECT_EQ(kVideoRotation_270, ConvertCVOByteToVideoRotation(3)); + // Test extracting rotation when Camera (C) and Flip (F) bits are set. + const int flip_bit = 1 << 2; + const int camera_bit = 1 << 3; + EXPECT_EQ(kVideoRotation_0, + ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 0)); + EXPECT_EQ(kVideoRotation_90, + ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 1)); + EXPECT_EQ(kVideoRotation_180, + ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 2)); + EXPECT_EQ(kVideoRotation_270, + ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3)); +} + +TEST_P(RtpSenderVideoTest, RetransmissionTypesGeneric) { + RTPVideoHeader header; + header.codec = kRtpVideoGeneric; + + EXPECT_EQ(kDontRetransmit, + rtp_sender_video_->GetStorageType( + header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, + rtp_sender_video_->GetStorageType( + header, kConditionallyRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitAllPackets, + kDefaultExpectedRetransmissionTimeMs)); +} + +TEST_P(RtpSenderVideoTest, RetransmissionTypesH264) { + RTPVideoHeader header; + header.codec = kRtpVideoH264; + header.codecHeader.H264.packetization_mode = + H264PacketizationMode::NonInterleaved; + + EXPECT_EQ(kDontRetransmit, + rtp_sender_video_->GetStorageType( + header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, + rtp_sender_video_->GetStorageType( + header, kConditionallyRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitAllPackets, + kDefaultExpectedRetransmissionTimeMs)); +} + +TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8BaseLayer) { + RTPVideoHeader header; + header.codec = kRtpVideoVp8; + header.codecHeader.VP8.temporalIdx = 0; + + EXPECT_EQ(kDontRetransmit, + rtp_sender_video_->GetStorageType( + header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, + rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers | kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( + header, kConditionallyRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ( + kAllowRetransmission, + rtp_sender_video_->GetStorageType( + header, kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitAllPackets, + kDefaultExpectedRetransmissionTimeMs)); +} + +TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8HigherLayers) { + RTPVideoHeader header; + header.codec = kRtpVideoVp8; + + for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) { + header.codecHeader.VP8.temporalIdx = tid; + + EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( + header, kRetransmitOff, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( + header, kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, + rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers | kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitAllPackets, + kDefaultExpectedRetransmissionTimeMs)); + } +} + +TEST_P(RtpSenderVideoTest, RetransmissionTypesVP9) { + RTPVideoHeader header; + header.codec = kRtpVideoVp9; + + for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) { + header.codecHeader.VP9.temporal_idx = tid; + + EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( + header, kRetransmitOff, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( + header, kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, + rtp_sender_video_->GetStorageType( + header, kRetransmitHigherLayers | kRetransmitBaseLayer, + kDefaultExpectedRetransmissionTimeMs)); + EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( + header, kRetransmitAllPackets, + kDefaultExpectedRetransmissionTimeMs)); + } +} + +TEST_P(RtpSenderVideoTest, ConditionalRetransmit) { + const int64_t kFrameIntervalMs = 33; + const int64_t kRttMs = (kFrameIntervalMs * 3) / 2; + const uint8_t kSettings = + kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers; + + // Insert VP8 frames for all temporal layers, but stop before the final index. + RTPVideoHeader header; + header.codec = kRtpVideoVp8; + + // Fill averaging window to prevent rounding errors. + constexpr int kNumRepetitions = + (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) / + kFrameIntervalMs; + constexpr int kPattern[] = {0, 2, 1, 2}; + for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) { + header.codecHeader.VP8.temporalIdx = kPattern[i % arraysize(kPattern)]; + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs); + fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + } + + // Since we're at the start of the pattern, the next expected frame in TL0 is + // right now. We will wait at most one expected retransmission time before + // acknowledging that it did not arrive, which means this frame and the next + // will not be retransmitted. + header.codecHeader.VP8.temporalIdx = 1; + EXPECT_EQ(StorageType::kDontRetransmit, + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); + fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + EXPECT_EQ(StorageType::kDontRetransmit, + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); + fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + + // The TL0 frame did not arrive. So allow retransmission. + EXPECT_EQ(StorageType::kAllowRetransmission, + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); + fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + + // Insert a frame for TL2. We just had frame in TL1, so the next one there is + // in three frames away. TL0 is still too far in the past. So, allow + // retransmission. + header.codecHeader.VP8.temporalIdx = 2; + EXPECT_EQ(StorageType::kAllowRetransmission, + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); + fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + + // Another TL2, next in TL1 is two frames away. Allow again. + EXPECT_EQ(StorageType::kAllowRetransmission, + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); + fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + + // Yet another TL2, next in TL1 is now only one frame away, so don't store + // for retransmission. + EXPECT_EQ(StorageType::kDontRetransmit, + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); +} + +TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) { + const int64_t kFrameIntervalMs = 200; + const int64_t kRttMs = (kFrameIntervalMs * 3) / 2; + const int32_t kSettings = + kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers; + + // Insert VP8 frames for all temporal layers, but stop before the final index. + RTPVideoHeader header; + header.codec = kRtpVideoVp8; + + // Fill averaging window to prevent rounding errors. + constexpr int kNumRepetitions = + (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) / + kFrameIntervalMs; + constexpr int kPattern[] = {0, 2, 2, 2}; + for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) { + header.codecHeader.VP8.temporalIdx = kPattern[i % arraysize(kPattern)]; + + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs); + fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + } + + // Since we're at the start of the pattern, the next expected frame will be + // right now in TL0. Put it in TL1 instead. Regular rules would dictate that + // we don't store for retransmission because we expect a frame in a lower + // layer, but that last frame in TL1 was a long time ago in absolute terms, + // so allow retransmission anyway. + header.codecHeader.VP8.temporalIdx = 1; + EXPECT_EQ(StorageType::kAllowRetransmission, + rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); +} + +TEST_P(RtpSenderTest, OnOverheadChanged) { + MockOverheadObserver mock_overhead_observer; + rtp_sender_.reset( + new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + &retransmission_rate_limiter_, &mock_overhead_observer)); + rtp_sender_->SetSSRC(kSsrc); + + // RTP overhead is 12B. + EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(12)).Times(1); + SendGenericPayload(); + + rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset, + kTransmissionTimeOffsetExtensionId); + + // TransmissionTimeOffset extension has a size of 8B. + // 12B + 8B = 20B + EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(20)).Times(1); + SendGenericPayload(); +} + +TEST_P(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) { + MockOverheadObserver mock_overhead_observer; + rtp_sender_.reset( + new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + &retransmission_rate_limiter_, &mock_overhead_observer)); + rtp_sender_->SetSSRC(kSsrc); + + EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1); + SendGenericPayload(); + SendGenericPayload(); +} + +TEST_P(RtpSenderTest, SendAudioPadding) { + MockTransport transport; + const bool kEnableAudio = true; + rtp_sender_.reset(new RTPSender( + kEnableAudio, &fake_clock_, &transport, &mock_paced_sender_, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, + nullptr, &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSendPayloadType(kPayload); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetTimestampOffset(0); + rtp_sender_->SetSSRC(kSsrc); + + const size_t kPaddingSize = 59; + EXPECT_CALL(transport, SendRtp(_, kPaddingSize + kRtpHeaderSize, _)) + .WillOnce(testing::Return(true)); + EXPECT_EQ(kPaddingSize, + rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo())); + + // Requested padding size is too small, will send a larger one. + const size_t kMinPaddingSize = 50; + EXPECT_CALL(transport, SendRtp(_, kMinPaddingSize + kRtpHeaderSize, _)) + .WillOnce(testing::Return(true)); + EXPECT_EQ( + kMinPaddingSize, + rtp_sender_->TimeToSendPadding(kMinPaddingSize - 5, PacedPacketInfo())); +} + +TEST_P(RtpSenderTest, SendsKeepAlive) { + MockTransport transport; + rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &mock_rtc_event_log_, nullptr, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSendPayloadType(kPayload); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetTimestampOffset(0); + rtp_sender_->SetSSRC(kSsrc); + + const uint8_t kKeepalivePayloadType = 20; + RTC_CHECK_NE(kKeepalivePayloadType, kPayload); + + EXPECT_CALL(transport, SendRtp(_, _, _)) + .WillOnce( + Invoke([&kKeepalivePayloadType](const uint8_t* packet, size_t len, + const PacketOptions& options) { + webrtc::RTPHeader rtp_header; + RtpUtility::RtpHeaderParser parser(packet, len); + EXPECT_TRUE(parser.Parse(&rtp_header, nullptr)); + EXPECT_FALSE(rtp_header.markerBit); + EXPECT_EQ(0U, rtp_header.paddingLength); + EXPECT_EQ(kKeepalivePayloadType, rtp_header.payloadType); + EXPECT_EQ(kSeqNum, rtp_header.sequenceNumber); + EXPECT_EQ(kSsrc, rtp_header.ssrc); + EXPECT_EQ(0u, len - rtp_header.headerLength); + return true; + })); + + rtp_sender_->SendKeepAlive(kKeepalivePayloadType); + EXPECT_EQ(kSeqNum + 1, rtp_sender_->SequenceNumber()); +} + +INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead, + RtpSenderTest, + ::testing::Bool()); +INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead, + RtpSenderTestWithoutPacer, + ::testing::Bool()); +INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead, + RtpSenderVideoTest, + ::testing::Bool()); +INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead, + RtpSenderAudioTest, + ::testing::Bool()); +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc new file mode 100644 index 0000000000..d2bef51b11 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -0,0 +1,554 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_sender_video.h" + +#include <stdlib.h> +#include <string.h> + +#include <limits> +#include <memory> +#include <utility> +#include <vector> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_format_video_generic.h" +#include "modules/rtp_rtcp/source/rtp_format_vp8.h" +#include "modules/rtp_rtcp/source/rtp_format_vp9.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/trace_event.h" + +namespace webrtc { + +namespace { +constexpr size_t kRedForFecHeaderLength = 1; +constexpr int64_t kMaxUnretransmittableFrameIntervalMs = 33 * 4; + +void BuildRedPayload(const RtpPacketToSend& media_packet, + RtpPacketToSend* red_packet) { + uint8_t* red_payload = red_packet->AllocatePayload( + kRedForFecHeaderLength + media_packet.payload_size()); + RTC_DCHECK(red_payload); + red_payload[0] = media_packet.PayloadType(); + + auto media_payload = media_packet.payload(); + memcpy(&red_payload[kRedForFecHeaderLength], media_payload.data(), + media_payload.size()); +} +} // namespace + +RTPSenderVideo::RTPSenderVideo(Clock* clock, + RTPSender* rtp_sender, + FlexfecSender* flexfec_sender) + : rtp_sender_(rtp_sender), + clock_(clock), + video_type_(kRtpVideoGeneric), + retransmission_settings_(kRetransmitBaseLayer | + kConditionallyRetransmitHigherLayers), + last_rotation_(kVideoRotation_0), + red_payload_type_(-1), + ulpfec_payload_type_(-1), + flexfec_sender_(flexfec_sender), + delta_fec_params_{0, 1, kFecMaskRandom}, + key_fec_params_{0, 1, kFecMaskRandom}, + fec_bitrate_(1000, RateStatistics::kBpsScale), + video_bitrate_(1000, RateStatistics::kBpsScale) {} + +RTPSenderVideo::~RTPSenderVideo() {} + +void RTPSenderVideo::SetVideoCodecType(RtpVideoCodecTypes video_type) { + video_type_ = video_type; +} + +RtpVideoCodecTypes RTPSenderVideo::VideoCodecType() const { + return video_type_; +} + +// Static. +RtpUtility::Payload* RTPSenderVideo::CreateVideoPayload( + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + int8_t payload_type) { + RtpVideoCodecTypes video_type = kRtpVideoGeneric; + if (RtpUtility::StringCompare(payload_name, "VP8", 3)) { + video_type = kRtpVideoVp8; + } else if (RtpUtility::StringCompare(payload_name, "VP9", 3)) { + video_type = kRtpVideoVp9; + } else if (RtpUtility::StringCompare(payload_name, "H264", 4)) { + video_type = kRtpVideoH264; + } else if (RtpUtility::StringCompare(payload_name, "I420", 4)) { + video_type = kRtpVideoGeneric; + } else { + video_type = kRtpVideoGeneric; + } + VideoPayload vp; + vp.videoCodecType = video_type; + return new RtpUtility::Payload(payload_name, PayloadUnion(vp)); +} + +void RTPSenderVideo::SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet, + StorageType storage) { + // Remember some values about the packet before sending it away. + size_t packet_size = packet->size(); + uint16_t seq_num = packet->SequenceNumber(); + uint32_t rtp_timestamp = packet->Timestamp(); + if (!rtp_sender_->SendToNetwork(std::move(packet), storage, + RtpPacketSender::kLowPriority)) { + RTC_LOG(LS_WARNING) << "Failed to send video packet " << seq_num; + return; + } + rtc::CritScope cs(&stats_crit_); + video_bitrate_.Update(packet_size, clock_->TimeInMilliseconds()); + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "Video::PacketNormal", "timestamp", rtp_timestamp, + "seqnum", seq_num); +} + +void RTPSenderVideo::SendVideoPacketAsRedMaybeWithUlpfec( + std::unique_ptr<RtpPacketToSend> media_packet, + StorageType media_packet_storage, + bool protect_media_packet) { + uint32_t rtp_timestamp = media_packet->Timestamp(); + uint16_t media_seq_num = media_packet->SequenceNumber(); + + std::unique_ptr<RtpPacketToSend> red_packet( + new RtpPacketToSend(*media_packet)); + BuildRedPayload(*media_packet, red_packet.get()); + + std::vector<std::unique_ptr<RedPacket>> fec_packets; + StorageType fec_storage = kDontRetransmit; + { + // Only protect while creating RED and FEC packets, not when sending. + rtc::CritScope cs(&crit_); + red_packet->SetPayloadType(red_payload_type_); + if (ulpfec_enabled()) { + if (protect_media_packet) { + ulpfec_generator_.AddRtpPacketAndGenerateFec( + media_packet->data(), media_packet->payload_size(), + media_packet->headers_size()); + } + uint16_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets(); + if (num_fec_packets > 0) { + uint16_t first_fec_sequence_number = + rtp_sender_->AllocateSequenceNumber(num_fec_packets); + fec_packets = ulpfec_generator_.GetUlpfecPacketsAsRed( + red_payload_type_, ulpfec_payload_type_, first_fec_sequence_number, + media_packet->headers_size()); + RTC_DCHECK_EQ(num_fec_packets, fec_packets.size()); + if (retransmission_settings_ & kRetransmitFECPackets) + fec_storage = kAllowRetransmission; + } + } + } + // Send |red_packet| instead of |packet| for allocated sequence number. + size_t red_packet_size = red_packet->size(); + if (rtp_sender_->SendToNetwork(std::move(red_packet), media_packet_storage, + RtpPacketSender::kLowPriority)) { + rtc::CritScope cs(&stats_crit_); + video_bitrate_.Update(red_packet_size, clock_->TimeInMilliseconds()); + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "Video::PacketRed", "timestamp", rtp_timestamp, + "seqnum", media_seq_num); + } else { + RTC_LOG(LS_WARNING) << "Failed to send RED packet " << media_seq_num; + } + for (const auto& fec_packet : fec_packets) { + // TODO(danilchap): Make ulpfec_generator_ generate RtpPacketToSend to avoid + // reparsing them. + std::unique_ptr<RtpPacketToSend> rtp_packet( + new RtpPacketToSend(*media_packet)); + RTC_CHECK(rtp_packet->Parse(fec_packet->data(), fec_packet->length())); + rtp_packet->set_capture_time_ms(media_packet->capture_time_ms()); + uint16_t fec_sequence_number = rtp_packet->SequenceNumber(); + if (rtp_sender_->SendToNetwork(std::move(rtp_packet), fec_storage, + RtpPacketSender::kLowPriority)) { + rtc::CritScope cs(&stats_crit_); + fec_bitrate_.Update(fec_packet->length(), clock_->TimeInMilliseconds()); + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "Video::PacketUlpfec", "timestamp", rtp_timestamp, + "seqnum", fec_sequence_number); + } else { + RTC_LOG(LS_WARNING) << "Failed to send ULPFEC packet " + << fec_sequence_number; + } + } +} + +void RTPSenderVideo::SendVideoPacketWithFlexfec( + std::unique_ptr<RtpPacketToSend> media_packet, + StorageType media_packet_storage, + bool protect_media_packet) { + RTC_DCHECK(flexfec_sender_); + + if (protect_media_packet) + flexfec_sender_->AddRtpPacketAndGenerateFec(*media_packet); + + SendVideoPacket(std::move(media_packet), media_packet_storage); + + if (flexfec_sender_->FecAvailable()) { + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = + flexfec_sender_->GetFecPackets(); + for (auto& fec_packet : fec_packets) { + size_t packet_length = fec_packet->size(); + uint32_t timestamp = fec_packet->Timestamp(); + uint16_t seq_num = fec_packet->SequenceNumber(); + if (rtp_sender_->SendToNetwork(std::move(fec_packet), kDontRetransmit, + RtpPacketSender::kLowPriority)) { + rtc::CritScope cs(&stats_crit_); + fec_bitrate_.Update(packet_length, clock_->TimeInMilliseconds()); + TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), + "Video::PacketFlexfec", "timestamp", timestamp, + "seqnum", seq_num); + } else { + RTC_LOG(LS_WARNING) << "Failed to send FlexFEC packet " << seq_num; + } + } + } +} + +void RTPSenderVideo::SetUlpfecConfig(int red_payload_type, + int ulpfec_payload_type) { + // Sanity check. Per the definition of UlpfecConfig (see config.h), + // a payload type of -1 means that the corresponding feature is + // turned off. + RTC_DCHECK_GE(red_payload_type, -1); + RTC_DCHECK_LE(red_payload_type, 127); + RTC_DCHECK_GE(ulpfec_payload_type, -1); + RTC_DCHECK_LE(ulpfec_payload_type, 127); + + rtc::CritScope cs(&crit_); + red_payload_type_ = red_payload_type; + ulpfec_payload_type_ = ulpfec_payload_type; + + // Must not enable ULPFEC without RED. + // TODO(brandtr): We currently support enabling RED without ULPFEC. Change + // this when we have removed the RED/RTX send-side workaround, so that we + // ensure that RED and ULPFEC are only enabled together. + RTC_DCHECK(red_enabled() || !ulpfec_enabled()); + + // Reset FEC parameters. + delta_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom}; + key_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom}; +} + +void RTPSenderVideo::GetUlpfecConfig(int* red_payload_type, + int* ulpfec_payload_type) const { + rtc::CritScope cs(&crit_); + *red_payload_type = red_payload_type_; + *ulpfec_payload_type = ulpfec_payload_type_; +} + +size_t RTPSenderVideo::CalculateFecPacketOverhead() const { + if (flexfec_enabled()) + return flexfec_sender_->MaxPacketOverhead(); + + size_t overhead = 0; + if (red_enabled()) { + // The RED overhead is due to a small header. + overhead += kRedForFecHeaderLength; + } + if (ulpfec_enabled()) { + // For ULPFEC, the overhead is the FEC headers plus RED for FEC header + // (see above) plus anything in RTP header beyond the 12 bytes base header + // (CSRC list, extensions...) + // This reason for the header extensions to be included here is that + // from an FEC viewpoint, they are part of the payload to be protected. + // (The base RTP header is already protected by the FEC header.) + overhead += ulpfec_generator_.MaxPacketOverhead() + + (rtp_sender_->RtpHeaderLength() - kRtpHeaderSize); + } + return overhead; +} + +void RTPSenderVideo::SetFecParameters(const FecProtectionParams& delta_params, + const FecProtectionParams& key_params) { + rtc::CritScope cs(&crit_); + delta_fec_params_ = delta_params; + key_fec_params_ = key_params; +} + +rtc::Optional<uint32_t> RTPSenderVideo::FlexfecSsrc() const { + if (flexfec_sender_) { + return flexfec_sender_->ssrc(); + } + return rtc::nullopt; +} + +bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type, + FrameType frame_type, + int8_t payload_type, + uint32_t rtp_timestamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* video_header, + int64_t expected_retransmission_time_ms, + const StreamId* rtpStreamId, + const StreamId* mId) { + if (payload_size == 0) + return false; + + // Create header that will be reused in all packets. + std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket(); + rtp_header->SetPayloadType(payload_type); + rtp_header->SetTimestamp(rtp_timestamp); + rtp_header->set_capture_time_ms(capture_time_ms); + + if (rtpStreamId && !rtpStreamId->empty()) { + rtp_header->SetExtension<RtpStreamId>(*rtpStreamId); + } + if (mId && !mId->empty()) { + rtp_header->SetExtension<RtpMid>(*mId); + } + + auto last_packet = rtc::MakeUnique<RtpPacketToSend>(*rtp_header); + + size_t fec_packet_overhead; + bool red_enabled; + int32_t retransmission_settings; + { + rtc::CritScope cs(&crit_); + // According to + // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ + // ts_126114v120700p.pdf Section 7.4.5: + // The MTSI client shall add the payload bytes as defined in this clause + // onto the last RTP packet in each group of packets which make up a key + // frame (I-frame or IDR frame in H.264 (AVC), or an IRAP picture in H.265 + // (HEVC)). The MTSI client may also add the payload bytes onto the last RTP + // packet in each group of packets which make up another type of frame + // (e.g. a P-Frame) only if the current value is different from the previous + // value sent. + if (video_header) { + // Set rotation when key frame or when changed (to follow standard). + // Or when different from 0 (to follow current receiver implementation). + VideoRotation current_rotation = video_header->rotation; + if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ || + current_rotation != kVideoRotation_0) + last_packet->SetExtension<VideoOrientation>(current_rotation); + last_rotation_ = current_rotation; + // Report content type only for key frames. + if (frame_type == kVideoFrameKey && + video_header->content_type != VideoContentType::UNSPECIFIED) { + last_packet->SetExtension<VideoContentTypeExtension>( + video_header->content_type); + } + if (video_header->video_timing.flags != TimingFrameFlags::kInvalid) { + last_packet->SetExtension<VideoTimingExtension>( + video_header->video_timing); + } + } + + // FEC settings. + const FecProtectionParams& fec_params = + frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_; + if (flexfec_enabled()) + flexfec_sender_->SetFecParameters(fec_params); + if (ulpfec_enabled()) + ulpfec_generator_.SetFecParameters(fec_params); + + fec_packet_overhead = CalculateFecPacketOverhead(); + red_enabled = this->red_enabled(); + retransmission_settings = retransmission_settings_; + } + + size_t packet_capacity = rtp_sender_->MaxRtpPacketSize() - + fec_packet_overhead - + (rtp_sender_->RtxStatus() ? kRtxHeaderSize : 0); + RTC_DCHECK_LE(packet_capacity, rtp_header->capacity()); + RTC_DCHECK_GT(packet_capacity, rtp_header->headers_size()); + RTC_DCHECK_GT(packet_capacity, last_packet->headers_size()); + size_t max_data_payload_length = packet_capacity - rtp_header->headers_size(); + RTC_DCHECK_GE(last_packet->headers_size(), rtp_header->headers_size()); + size_t last_packet_reduction_len = + last_packet->headers_size() - rtp_header->headers_size(); + + std::unique_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create( + video_type, max_data_payload_length, last_packet_reduction_len, + video_header ? &(video_header->codecHeader) : nullptr, frame_type)); + + const uint8_t temporal_id = + video_header ? GetTemporalId(*video_header) : kNoTemporalIdx; + StorageType storage = GetStorageType(temporal_id, retransmission_settings, + expected_retransmission_time_ms); + + size_t num_packets = + packetizer->SetPayloadData(payload_data, payload_size, fragmentation); + + if (num_packets == 0) + return false; + + bool first_frame = first_frame_sent_(); + for (size_t i = 0; i < num_packets; ++i) { + bool last = (i + 1) == num_packets; + auto packet = last ? std::move(last_packet) + : rtc::MakeUnique<RtpPacketToSend>(*rtp_header); + if (!packetizer->NextPacket(packet.get())) + return false; + RTC_DCHECK_LE(packet->payload_size(), + last ? max_data_payload_length - last_packet_reduction_len + : max_data_payload_length); + if (!rtp_sender_->AssignSequenceNumber(packet.get())) + return false; + + // No FEC protection for upper temporal layers, if used. + bool protect_packet = temporal_id == 0 || temporal_id == kNoTemporalIdx; + + // Put packetization finish timestamp into extension. + if (packet->HasExtension<VideoTimingExtension>()) { + packet->set_packetization_finish_time_ms(clock_->TimeInMilliseconds()); + // TODO(ilnik): Due to webrtc:7859, packets with timing extensions are not + // protected by FEC. It reduces FEC efficiency a bit. When FEC is moved + // below the pacer, it can be re-enabled for these packets. + // NOTE: Any RTP stream processor in the network, modifying 'network' + // timestamps in the timing frames extension have to be an end-point for + // FEC, otherwise recovered by FEC packets will be corrupted. + protect_packet = false; + } + + if (flexfec_enabled()) { + // TODO(brandtr): Remove the FlexFEC code path when FlexfecSender + // is wired up to PacedSender instead. + SendVideoPacketWithFlexfec(std::move(packet), storage, protect_packet); + } else if (red_enabled) { + SendVideoPacketAsRedMaybeWithUlpfec(std::move(packet), storage, + protect_packet); + } else { + SendVideoPacket(std::move(packet), storage); + } + + if (first_frame) { + if (i == 0) { + RTC_LOG(LS_INFO) + << "Sent first RTP packet of the first video frame (pre-pacer)"; + } + if (last) { + RTC_LOG(LS_INFO) + << "Sent last RTP packet of the first video frame (pre-pacer)"; + } + } + } + + TRACE_EVENT_ASYNC_END1("webrtc", "Video", capture_time_ms, "timestamp", + rtp_timestamp); + return true; +} + +uint32_t RTPSenderVideo::VideoBitrateSent() const { + rtc::CritScope cs(&stats_crit_); + return video_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0); +} + +uint32_t RTPSenderVideo::FecOverheadRate() const { + rtc::CritScope cs(&stats_crit_); + return fec_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0); +} + +int RTPSenderVideo::SelectiveRetransmissions() const { + rtc::CritScope cs(&crit_); + return retransmission_settings_; +} + +void RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) { + rtc::CritScope cs(&crit_); + retransmission_settings_ = settings; +} + +StorageType RTPSenderVideo::GetStorageType( + uint8_t temporal_id, + int32_t retransmission_settings, + int64_t expected_retransmission_time_ms) { + if (retransmission_settings == kRetransmitOff) + return StorageType::kDontRetransmit; + if (retransmission_settings == kRetransmitAllPackets) + return StorageType::kAllowRetransmission; + + rtc::CritScope cs(&stats_crit_); + // Media packet storage. + if ((retransmission_settings & kConditionallyRetransmitHigherLayers) && + UpdateConditionalRetransmit(temporal_id, + expected_retransmission_time_ms)) { + retransmission_settings |= kRetransmitHigherLayers; + } + + if (temporal_id == kNoTemporalIdx) + return kAllowRetransmission; + + if ((retransmission_settings & kRetransmitBaseLayer) && temporal_id == 0) + return kAllowRetransmission; + + if ((retransmission_settings & kRetransmitHigherLayers) && temporal_id > 0) + return kAllowRetransmission; + + return kDontRetransmit; +} + +uint8_t RTPSenderVideo::GetTemporalId(const RTPVideoHeader& header) { + switch (header.codec) { + case kRtpVideoVp8: + return header.codecHeader.VP8.temporalIdx; + case kRtpVideoVp9: + return header.codecHeader.VP9.temporal_idx; + default: + return kNoTemporalIdx; + } +} + +bool RTPSenderVideo::UpdateConditionalRetransmit( + uint8_t temporal_id, + int64_t expected_retransmission_time_ms) { + int64_t now_ms = clock_->TimeInMilliseconds(); + // Update stats for any temporal layer. + TemporalLayerStats* current_layer_stats = + &frame_stats_by_temporal_layer_[temporal_id]; + current_layer_stats->frame_rate_fp1000s.Update(1, now_ms); + int64_t tl_frame_interval = now_ms - current_layer_stats->last_frame_time_ms; + current_layer_stats->last_frame_time_ms = now_ms; + + // Conditional retransmit only applies to upper layers. + if (temporal_id != kNoTemporalIdx && temporal_id > 0) { + if (tl_frame_interval >= kMaxUnretransmittableFrameIntervalMs) { + // Too long since a retransmittable frame in this layer, enable NACK + // protection. + return true; + } else { + // Estimate when the next frame of any lower layer will be sent. + const int64_t kUndefined = std::numeric_limits<int64_t>::max(); + int64_t expected_next_frame_time = kUndefined; + for (int i = temporal_id - 1; i >= 0; --i) { + TemporalLayerStats* stats = &frame_stats_by_temporal_layer_[i]; + rtc::Optional<uint32_t> rate = stats->frame_rate_fp1000s.Rate(now_ms); + if (rate) { + int64_t tl_next = stats->last_frame_time_ms + 1000000 / *rate; + if (tl_next - now_ms > -expected_retransmission_time_ms && + tl_next < expected_next_frame_time) { + expected_next_frame_time = tl_next; + } + } + } + + if (expected_next_frame_time == kUndefined || + expected_next_frame_time - now_ms > expected_retransmission_time_ms) { + // The next frame in a lower layer is expected at a later time (or + // unable to tell due to lack of data) than a retransmission is + // estimated to be able to arrive, so allow this packet to be nacked. + return true; + } + } + } + + return false; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h new file mode 100644 index 0000000000..1db1ba4000 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h @@ -0,0 +1,169 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_ + +#include <map> +#include <memory> + +#include "api/optional.h" +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/flexfec_sender.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "modules/rtp_rtcp/source/rtp_sender.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "modules/rtp_rtcp/source/ulpfec_generator.h" +#include "modules/rtp_rtcp/source/video_codec_information.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/onetimeevent.h" +#include "rtc_base/rate_statistics.h" +#include "rtc_base/sequenced_task_checker.h" +#include "rtc_base/thread_annotations.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { +class RtpPacketizer; +class RtpPacketToSend; + +class RTPSenderVideo { + public: + static constexpr int64_t kTLRateWindowSizeMs = 2500; + + RTPSenderVideo(Clock* clock, + RTPSender* rtpSender, + FlexfecSender* flexfec_sender); + virtual ~RTPSenderVideo(); + + virtual RtpVideoCodecTypes VideoCodecType() const; + + static RtpUtility::Payload* CreateVideoPayload( + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + int8_t payload_type); + + bool SendVideo(RtpVideoCodecTypes video_type, + FrameType frame_type, + int8_t payload_type, + uint32_t capture_timestamp, + int64_t capture_time_ms, + const uint8_t* payload_data, + size_t payload_size, + const RTPFragmentationHeader* fragmentation, + const RTPVideoHeader* video_header, + int64_t expected_retransmission_time_ms, + const StreamId* rtpStreamId, + const StreamId* mId); + + void SetVideoCodecType(RtpVideoCodecTypes type); + + // ULPFEC. + void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type); + void GetUlpfecConfig(int* red_payload_type, int* ulpfec_payload_type) const; + + // FlexFEC/ULPFEC. + void SetFecParameters(const FecProtectionParams& delta_params, + const FecProtectionParams& key_params); + + // FlexFEC. + rtc::Optional<uint32_t> FlexfecSsrc() const; + + uint32_t VideoBitrateSent() const; + uint32_t FecOverheadRate() const; + + int SelectiveRetransmissions() const; + void SetSelectiveRetransmissions(uint8_t settings); + + protected: + static uint8_t GetTemporalId(const RTPVideoHeader& header); + StorageType GetStorageType(uint8_t temporal_id, + int32_t retransmission_settings, + int64_t expected_retransmission_time_ms); + + private: + struct TemporalLayerStats { + TemporalLayerStats() + : frame_rate_fp1000s(kTLRateWindowSizeMs, 1000 * 1000), + last_frame_time_ms(0) {} + // Frame rate, in frames per 1000 seconds. This essentially turns the fps + // value into a fixed point value with three decimals. Improves precision at + // low frame rates. + RateStatistics frame_rate_fp1000s; + int64_t last_frame_time_ms; + }; + + size_t CalculateFecPacketOverhead() const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); + + void SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet, + StorageType storage); + + void SendVideoPacketAsRedMaybeWithUlpfec( + std::unique_ptr<RtpPacketToSend> media_packet, + StorageType media_packet_storage, + bool protect_media_packet); + + // TODO(brandtr): Remove the FlexFEC functions when FlexfecSender has been + // moved to PacedSender. + void SendVideoPacketWithFlexfec(std::unique_ptr<RtpPacketToSend> media_packet, + StorageType media_packet_storage, + bool protect_media_packet); + + bool red_enabled() const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_) { + return red_payload_type_ >= 0; + } + + bool ulpfec_enabled() const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_) { + return ulpfec_payload_type_ >= 0; + } + + bool flexfec_enabled() const { return flexfec_sender_ != nullptr; } + + bool UpdateConditionalRetransmit(uint8_t temporal_id, + int64_t expected_retransmission_time_ms) + RTC_EXCLUSIVE_LOCKS_REQUIRED(stats_crit_); + + RTPSender* const rtp_sender_; + Clock* const clock_; + + // Should never be held when calling out of this class. + rtc::CriticalSection crit_; + + RtpVideoCodecTypes video_type_; + int32_t retransmission_settings_ RTC_GUARDED_BY(crit_); + VideoRotation last_rotation_ RTC_GUARDED_BY(crit_); + + // RED/ULPFEC. + int red_payload_type_ RTC_GUARDED_BY(crit_); + int ulpfec_payload_type_ RTC_GUARDED_BY(crit_); + UlpfecGenerator ulpfec_generator_ RTC_GUARDED_BY(crit_); + + // FlexFEC. + FlexfecSender* const flexfec_sender_; + + // FEC parameters, applicable to either ULPFEC or FlexFEC. + FecProtectionParams delta_fec_params_ RTC_GUARDED_BY(crit_); + FecProtectionParams key_fec_params_ RTC_GUARDED_BY(crit_); + + rtc::CriticalSection stats_crit_; + // Bitrate used for FEC payload, RED headers, RTP headers for FEC packets + // and any padding overhead. + RateStatistics fec_bitrate_ RTC_GUARDED_BY(stats_crit_); + // Bitrate used for video payload and RTP headers. + RateStatistics video_bitrate_ RTC_GUARDED_BY(stats_crit_); + + std::map<int, TemporalLayerStats> frame_stats_by_temporal_layer_ + RTC_GUARDED_BY(stats_crit_); + + OneTimeEvent first_frame_sent_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.cc new file mode 100644 index 0000000000..a986464cda --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.cc @@ -0,0 +1,525 @@ +/* + * 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 "modules/rtp_rtcp/source/rtp_utility.h" + +#include "modules/rtp_rtcp/include/rtp_cvo.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +RtpFeedback* NullObjectRtpFeedback() { + static NullRtpFeedback null_rtp_feedback; + return &null_rtp_feedback; +} + +namespace RtpUtility { + +enum { + kRtcpExpectedVersion = 2, + kRtcpMinHeaderLength = 4, + kRtcpMinParseLength = 8, + + kRtpExpectedVersion = 2, + kRtpMinParseLength = 12 +}; + +/* + * Misc utility routines + */ + +#if defined(_WIN32) +bool StringCompare(const char* str1, const char* str2, + const uint32_t length) { + return _strnicmp(str1, str2, length) == 0; +} +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_BSD) || defined(WEBRTC_MAC) +bool StringCompare(const char* str1, const char* str2, + const uint32_t length) { + return strncasecmp(str1, str2, length) == 0; +} +#endif + +size_t Word32Align(size_t size) { + uint32_t remainder = size % 4; + if (remainder != 0) + return size + 4 - remainder; + return size; +} + +RtpHeaderParser::RtpHeaderParser(const uint8_t* rtpData, + const size_t rtpDataLength) + : _ptrRTPDataBegin(rtpData), + _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) { +} + +RtpHeaderParser::~RtpHeaderParser() { +} + +bool RtpHeaderParser::RTCP() const { + // 72 to 76 is reserved for RTP + // 77 to 79 is not reserver but they are not assigned we will block them + // for RTCP 200 SR == marker bit + 72 + // for RTCP 204 APP == marker bit + 76 + /* + * RTCP + * + * FIR full INTRA-frame request 192 [RFC2032] supported + * NACK negative acknowledgement 193 [RFC2032] + * IJ Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toff + * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07 + * SR sender report 200 [RFC3551] supported + * RR receiver report 201 [RFC3551] supported + * SDES source description 202 [RFC3551] supported + * BYE goodbye 203 [RFC3551] supported + * APP application-defined 204 [RFC3551] ignored + * RTPFB Transport layer FB message 205 [RFC4585] supported + * PSFB Payload-specific FB message 206 [RFC4585] supported + * XR extended report 207 [RFC3611] supported + */ + + /* 205 RFC 5104 + * FMT 1 NACK supported + * FMT 2 reserved + * FMT 3 TMMBR supported + * FMT 4 TMMBN supported + */ + + /* 206 RFC 5104 + * FMT 1: Picture Loss Indication (PLI) supported + * FMT 2: Slice Lost Indication (SLI) + * FMT 3: Reference Picture Selection Indication (RPSI) + * FMT 4: Full Intra Request (FIR) Command supported + * FMT 5: Temporal-Spatial Trade-off Request (TSTR) + * FMT 6: Temporal-Spatial Trade-off Notification (TSTN) + * FMT 7: Video Back Channel Message (VBCM) + * FMT 15: Application layer FB message + */ + + const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin; + if (length < kRtcpMinHeaderLength) { + return false; + } + + const uint8_t V = _ptrRTPDataBegin[0] >> 6; + if (V != kRtcpExpectedVersion) { + return false; + } + + const uint8_t payloadType = _ptrRTPDataBegin[1]; + switch (payloadType) { + case 192: + return true; + case 193: + // not supported + // pass through and check for a potential RTP packet + return false; + case 195: + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + case 207: + return true; + default: + return false; + } +} + +bool RtpHeaderParser::ParseRtcp(RTPHeader* header) const { + assert(header != NULL); + + const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin; + if (length < kRtcpMinParseLength) { + return false; + } + + const uint8_t V = _ptrRTPDataBegin[0] >> 6; + if (V != kRtcpExpectedVersion) { + return false; + } + + const uint8_t PT = _ptrRTPDataBegin[1]; + const size_t len = (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3]; + const uint8_t* ptr = &_ptrRTPDataBegin[4]; + + uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr); + ptr += 4; + + header->payloadType = PT; + header->ssrc = SSRC; + header->headerLength = 4 + (len << 2); + if (header->headerLength > static_cast<size_t>(length)) { + return false; + } + + return true; +} + +bool RtpHeaderParser::Parse(RTPHeader* header, + RtpHeaderExtensionMap* ptrExtensionMap, + bool secured) const { + const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin; + if (length < kRtpMinParseLength) { + return false; + } + + // Version + const uint8_t V = _ptrRTPDataBegin[0] >> 6; + // Padding + const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true; + // eXtension + const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true; + const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f; + const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true; + + const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f; + + const uint16_t sequenceNumber = (_ptrRTPDataBegin[2] << 8) + + _ptrRTPDataBegin[3]; + + const uint8_t* ptr = &_ptrRTPDataBegin[4]; + + uint32_t RTPTimestamp = ByteReader<uint32_t>::ReadBigEndian(ptr); + ptr += 4; + + uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr); + ptr += 4; + + if (V != kRtpExpectedVersion) { + return false; + } + + header->markerBit = M; + header->payloadType = PT; + header->sequenceNumber = sequenceNumber; + header->timestamp = RTPTimestamp; + header->ssrc = SSRC; + header->numCSRCs = CC; + header->paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0; + + // 12 == sizeof(RFC rtp header) == kRtpMinParseLength, each CSRC=4 bytes + header->headerLength = 12 + (CC * 4); + // not a full validation, just safety against underflow. Padding must + // start after the header. We can have 0 payload bytes left, note. + if (!secured && + (header->paddingLength + header->headerLength > (size_t) length)) { + return false; + } + + for (uint8_t i = 0; i < CC; ++i) { + uint32_t CSRC = ByteReader<uint32_t>::ReadBigEndian(ptr); + ptr += 4; + header->arrOfCSRCs[i] = CSRC; + } + assert((ptr - _ptrRTPDataBegin) == (ptrdiff_t) header->headerLength); + + // If in effect, MAY be omitted for those packets for which the offset + // is zero. + header->extension.hasTransmissionTimeOffset = false; + header->extension.transmissionTimeOffset = 0; + + // May not be present in packet. + header->extension.hasAbsoluteSendTime = false; + header->extension.absoluteSendTime = 0; + + // May not be present in packet. + header->extension.hasAudioLevel = false; + header->extension.voiceActivity = false; + header->extension.audioLevel = 0; + + // May not be present in packet. + header->extension.hasVideoRotation = false; + header->extension.videoRotation = kVideoRotation_0; + + // May not be present in packet. + header->extension.playout_delay.min_ms = -1; + header->extension.playout_delay.max_ms = -1; + + // May not be present in packet. + header->extension.hasVideoContentType = false; + header->extension.videoContentType = VideoContentType::UNSPECIFIED; + + header->extension.has_video_timing = false; + header->extension.video_timing = {0u, 0u, 0u, 0u, 0u, 0u, false}; + + if (X) { + /* RTP header extension, RFC 3550. + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | defined by profile | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | header extension | + | .... | + */ + // earlier test ensures we have at least paddingLength bytes left + const ptrdiff_t remain = (_ptrRTPDataEnd - ptr) - header->paddingLength; + if (remain < 4) { // minimum header extension length = 32 bits + return false; + } + + header->headerLength += 4; + + uint16_t definedByProfile = ByteReader<uint16_t>::ReadBigEndian(ptr); + ptr += 2; + + // in 32 bit words + size_t XLen = ByteReader<uint16_t>::ReadBigEndian(ptr); + ptr += 2; + XLen *= 4; // in bytes + + if (static_cast<size_t>(remain) < (4 + XLen)) { + return false; + } + static constexpr uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE; + if (definedByProfile == kRtpOneByteHeaderExtensionId) { + const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen; + ParseOneByteExtensionHeader(header, + ptrExtensionMap, + ptrRTPDataExtensionEnd, + ptr); + } + header->headerLength += XLen; + } + if (header->headerLength + header->paddingLength > + static_cast<size_t>(length)) + return false; + return true; +} + +void RtpHeaderParser::ParseOneByteExtensionHeader( + RTPHeader* header, + const RtpHeaderExtensionMap* ptrExtensionMap, + const uint8_t* ptrRTPDataExtensionEnd, + const uint8_t* ptr) const { + if (!ptrExtensionMap) { + return; + } + + while (ptrRTPDataExtensionEnd - ptr > 0) { + // 0 + // 0 1 2 3 4 5 6 7 + // +-+-+-+-+-+-+-+-+ + // | ID | len | + // +-+-+-+-+-+-+-+-+ + + // Note that 'len' is the header extension element length, which is the + // number of bytes - 1. + const int id = (*ptr & 0xf0) >> 4; + const int len = (*ptr & 0x0f); + if (ptr + len + 1 > ptrRTPDataExtensionEnd) { + RTC_LOG(LS_WARNING) + << "RTP extension header length out of bounds. Terminate parsing."; + return; + } + ptr++; + + if (id == 0) { + // Padding byte, skip ignoring len. + continue; + } + + if (id == 15) { + RTC_LOG(LS_VERBOSE) + << "RTP extension header 15 encountered. Terminate parsing."; + return; + } + + if (ptrRTPDataExtensionEnd - ptr < (len + 1)) { + RTC_LOG(LS_WARNING) << "Incorrect one-byte extension len: " << (len + 1) + << ", bytes left in buffer: " + << (ptrRTPDataExtensionEnd - ptr); + return; + } + + RTPExtensionType type = ptrExtensionMap->GetType(id); + if (type == RtpHeaderExtensionMap::kInvalidType) { + // If we encounter an unknown extension, just skip over it. + // Mozilla - we reuse the parse for demux, without registering extensions. + // Reduce log-spam by switching to VERBOSE + RTC_LOG(LS_VERBOSE) << "Failed to find extension id: " << id; + } else { + switch (type) { + case kRtpExtensionTransmissionTimeOffset: { + if (len != 2) { + RTC_LOG(LS_WARNING) + << "Incorrect transmission time offset len: " << len; + return; + } + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=2 | transmission offset | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + header->extension.transmissionTimeOffset = + ByteReader<int32_t, 3>::ReadBigEndian(ptr); + header->extension.hasTransmissionTimeOffset = true; + break; + } + case kRtpExtensionAudioLevel: { + if (len != 0) { + RTC_LOG(LS_WARNING) << "Incorrect audio level len: " << len; + return; + } + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=0 |V| level | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + header->extension.audioLevel = ptr[0] & 0x7f; + header->extension.voiceActivity = (ptr[0] & 0x80) != 0; + header->extension.hasAudioLevel = true; + break; + } + case kRtpExtensionAbsoluteSendTime: { + if (len != 2) { + RTC_LOG(LS_WARNING) << "Incorrect absolute send time len: " << len; + return; + } + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=2 | absolute send time | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + header->extension.absoluteSendTime = + ByteReader<uint32_t, 3>::ReadBigEndian(ptr); + header->extension.hasAbsoluteSendTime = true; + break; + } + case kRtpExtensionVideoRotation: { + if (len != 0) { + RTC_LOG(LS_WARNING) + << "Incorrect coordination of video coordination len: " << len; + return; + } + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=0 |0 0 0 0 C F R R| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + header->extension.hasVideoRotation = true; + header->extension.videoRotation = + ConvertCVOByteToVideoRotation(ptr[0]); + break; + } + case kRtpExtensionTransportSequenceNumber: { + if (len != 1) { + RTC_LOG(LS_WARNING) + << "Incorrect transport sequence number len: " << len; + return; + } + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | L=1 |transport wide sequence number | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + uint16_t sequence_number = ptr[0] << 8; + sequence_number += ptr[1]; + header->extension.transportSequenceNumber = sequence_number; + header->extension.hasTransportSequenceNumber = true; + break; + } + case kRtpExtensionPlayoutDelay: { + if (len != 2) { + RTC_LOG(LS_WARNING) << "Incorrect playout delay len: " << len; + return; + } + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=2 | MIN delay | MAX delay | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + int min_playout_delay = (ptr[0] << 4) | ((ptr[1] >> 4) & 0xf); + int max_playout_delay = ((ptr[1] & 0xf) << 8) | ptr[2]; + header->extension.playout_delay.min_ms = + min_playout_delay * PlayoutDelayLimits::kGranularityMs; + header->extension.playout_delay.max_ms = + max_playout_delay * PlayoutDelayLimits::kGranularityMs; + break; + } + case kRtpExtensionVideoContentType: { + if (len != 0) { + RTC_LOG(LS_WARNING) << "Incorrect video content type len: " << len; + return; + } + // 0 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | len=0 | Content type | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (videocontenttypehelpers::IsValidContentType(ptr[0])) { + header->extension.hasVideoContentType = true; + header->extension.videoContentType = + static_cast<VideoContentType>(ptr[0]); + } + break; + } + case kRtpExtensionVideoTiming: { + if (len != VideoTimingExtension::kValueSizeBytes - 1) { + RTC_LOG(LS_WARNING) << "Incorrect video timing len: " << len; + return; + } + header->extension.has_video_timing = true; + VideoTimingExtension::Parse(rtc::MakeArrayView(ptr, len + 1), + &header->extension.video_timing); + break; + } + case kRtpExtensionRtpStreamId: { + header->extension.stream_id.Set(rtc::MakeArrayView(ptr, len + 1)); + break; + } + case kRtpExtensionRepairedRtpStreamId: { + header->extension.repaired_stream_id.Set( + rtc::MakeArrayView(ptr, len + 1)); + break; + } + case kRtpExtensionMid: { + header->extension.mid.Set(rtc::MakeArrayView(ptr, len + 1)); + break; + } + case kRtpExtensionCsrcAudioLevel: { + auto& levels = header->extension.csrcAudioLevels; + levels.numAudioLevels = static_cast<uint8_t>(len + 1); + if (levels.numAudioLevels > kRtpCsrcSize) { + RTC_LOG(LS_WARNING) << "Incorrect number of CSRC audio levels: " << + levels.numAudioLevels; + levels.numAudioLevels = 0; + return; + } + for (uint8_t i = 0; i < levels.numAudioLevels; i++) { + levels.arrOfAudioLevels[i] = ptr[i] & 0x7f; + } + break; + } + case kRtpExtensionNone: + case kRtpExtensionNumberOfExtensions: { + RTC_NOTREACHED() << "Invalid extension type: " << type; + return; + } + } + } + ptr += (len + 1); + } +} + +} // namespace RtpUtility +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.h new file mode 100644 index 0000000000..15634aa02b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.h @@ -0,0 +1,69 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_RTP_UTILITY_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_UTILITY_H_ + +#include <cstring> +#include <map> + +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "rtc_base/deprecation.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +const uint8_t kRtpMarkerBitMask = 0x80; + +RtpFeedback* NullObjectRtpFeedback(); + +namespace RtpUtility { + +struct Payload { + Payload(const char* name, const PayloadUnion& pu) : typeSpecific(pu) { + std::strncpy(this->name, name, sizeof(this->name) - 1); + this->name[sizeof(this->name) - 1] = '\0'; + } + char name[RTP_PAYLOAD_NAME_SIZE]; + PayloadUnion typeSpecific; +}; + +bool StringCompare(const char* str1, const char* str2, const uint32_t length); + +// Round up to the nearest size that is a multiple of 4. +size_t Word32Align(size_t size); + +class RtpHeaderParser { + public: + RtpHeaderParser(const uint8_t* rtpData, size_t rtpDataLength); + ~RtpHeaderParser(); + + bool RTCP() const; + bool ParseRtcp(RTPHeader* header) const; + bool Parse(RTPHeader* parsedPacket, + RtpHeaderExtensionMap* ptrExtensionMap = nullptr, + bool secured = false) const; + + private: + void ParseOneByteExtensionHeader(RTPHeader* parsedPacket, + const RtpHeaderExtensionMap* ptrExtensionMap, + const uint8_t* ptrRTPDataExtensionEnd, + const uint8_t* ptr) const; + + const uint8_t* const _ptrRTPDataBegin; + const uint8_t* const _ptrRTPDataEnd; +}; +} // namespace RtpUtility +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_UTILITY_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc new file mode 100644 index 0000000000..24709bd25b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/rtp_utility.h" + +#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::ElementsAreArray; +using ::testing::make_tuple; + +const int8_t kPayloadType = 100; +const uint32_t kSsrc = 0x12345678; +const uint16_t kSeqNum = 88; +const uint32_t kTimestamp = 0x65431278; + +} // namespace + +TEST(RtpHeaderParser, ParseMinimum) { + // clang-format off + const uint8_t kPacket[] = { + 0x80, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78}; // kSsrc. + // clang-format on + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, nullptr)); + + EXPECT_EQ(kPayloadType, header.payloadType); + EXPECT_EQ(kSeqNum, header.sequenceNumber); + EXPECT_EQ(kTimestamp, header.timestamp); + EXPECT_EQ(kSsrc, header.ssrc); + EXPECT_EQ(0u, header.paddingLength); + EXPECT_EQ(sizeof(kPacket), header.headerLength); +} + +TEST(RtpHeaderParser, ParseWithExtension) { + // clang-format off + const uint8_t kPacket[] = { + 0x90, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0xbe, 0xde, 0x00, 0x01, // Extension block of size 1 x 32bit words. + 0x12, 0x01, 0x56, 0xce}; + // clang-format on + RtpHeaderExtensionMap extensions; + extensions.Register<TransmissionOffset>(1); + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, &extensions)); + + EXPECT_EQ(kPayloadType, header.payloadType); + EXPECT_EQ(kSeqNum, header.sequenceNumber); + EXPECT_EQ(kTimestamp, header.timestamp); + EXPECT_EQ(kSsrc, header.ssrc); + + ASSERT_TRUE(header.extension.hasTransmissionTimeOffset); + EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset); +} + +TEST(RtpHeaderParser, ParseWithInvalidSizedExtension) { + const size_t kPayloadSize = 7; + // clang-format off + const uint8_t kPacket[] = { + 0x90, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0xbe, 0xde, 0x00, 0x02, // Extension block of size 2 x 32bit words. + 0x16, // (6+1)-bytes, but Transmission Offset expected to be 3-bytes. + 'e', 'x', 't', + 'd', 'a', 't', 'a', + 'p', 'a', 'y', 'l', 'o', 'a', 'd' + }; + // clang-format on + RtpHeaderExtensionMap extensions; + extensions.Register<TransmissionOffset>(1); + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, &extensions)); + + // Extension should be ignored. + EXPECT_FALSE(header.extension.hasTransmissionTimeOffset); + // But shouldn't prevent reading payload. + EXPECT_THAT(sizeof(kPacket) - kPayloadSize, header.headerLength); +} + +TEST(RtpHeaderParser, ParseWithExtensionPadding) { + // clang-format off + const uint8_t kPacket[] = { + 0x90, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0xbe, 0xde, 0x00, 0x02, // Extension of size 1x32bit word. + 0x02, // A byte of (invalid) padding. + 0x12, 0x1a, 0xda, 0x03, // TransmissionOffset extension. + 0x0f, 0x00, 0x03, // More invalid padding bytes: id=0, but len > 0. + }; + // clang-format on + RtpHeaderExtensionMap extensions; + extensions.Register<TransmissionOffset>(1); + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, &extensions)); + + // Parse should skip padding and read extension. + EXPECT_TRUE(header.extension.hasTransmissionTimeOffset); + EXPECT_EQ(0x1ada03, header.extension.transmissionTimeOffset); + EXPECT_EQ(sizeof(kPacket), header.headerLength); +} + +TEST(RtpHeaderParser, ParseWithOverSizedExtension) { + // clang-format off + const uint8_t kPacket[] = { + 0x90, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0xbe, 0xde, 0x00, 0x01, // Extension of size 1x32bit word. + 0x00, // Add a byte of padding. + 0x12, // Extension id 1 size (2+1). + 0xda, 0x1a // Only 2 bytes of extension payload. + }; + // clang-format on + RtpHeaderExtensionMap extensions; + extensions.Register<TransmissionOffset>(1); + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, &extensions)); + + // Parse should ignore extension. + EXPECT_FALSE(header.extension.hasTransmissionTimeOffset); + EXPECT_EQ(sizeof(kPacket), header.headerLength); +} + +TEST(RtpHeaderParser, ParseAll8Extensions) { + const uint8_t kAudioLevel = 0x5a; + // clang-format off + const uint8_t kPacket[] = { + 0x90, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0xbe, 0xde, 0x00, 0x08, // Extension of size 8x32bit words. + 0x40, 0x80|kAudioLevel, // AudioLevel. + 0x22, 0x01, 0x56, 0xce, // TransmissionOffset. + 0x62, 0x12, 0x34, 0x56, // AbsoluteSendTime. + 0x72, 0x7f, 0x01, 0x10, // CsrcAudioLevel + 0x81, 0xce, 0xab, // TransportSequenceNumber. + 0xa0, 0x03, // VideoRotation. + 0xb2, 0x12, 0x48, 0x76, // PlayoutDelayLimits. + 0xc2, 'r', 't', 'x', // RtpStreamId + 0xd5, 's', 't', 'r', 'e', 'a', 'm', // RepairedRtpStreamId + 0x00, 0x00, // Padding to 32bit boundary. + }; + // clang-format on + ASSERT_EQ(sizeof(kPacket) % 4, 0u); + + RtpHeaderExtensionMap extensions; + extensions.Register<TransmissionOffset>(2); + extensions.Register<AudioLevel>(4); + extensions.Register<AbsoluteSendTime>(6); + extensions.Register<CsrcAudioLevel>(7); + extensions.Register<TransportSequenceNumber>(8); + extensions.Register<VideoOrientation>(0xa); + extensions.Register<PlayoutDelayLimits>(0xb); + extensions.Register<RtpStreamId>(0xc); + extensions.Register<RepairedRtpStreamId>(0xd); + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, &extensions)); + + EXPECT_TRUE(header.extension.hasTransmissionTimeOffset); + EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset); + + EXPECT_TRUE(header.extension.hasAudioLevel); + EXPECT_TRUE(header.extension.voiceActivity); + EXPECT_EQ(kAudioLevel, header.extension.audioLevel); + + EXPECT_TRUE(header.extension.hasAbsoluteSendTime); + EXPECT_EQ(0x123456U, header.extension.absoluteSendTime); + + EXPECT_TRUE(header.extension.hasTransportSequenceNumber); + EXPECT_EQ(0xceab, header.extension.transportSequenceNumber); + + EXPECT_TRUE(header.extension.hasVideoRotation); + EXPECT_EQ(kVideoRotation_270, header.extension.videoRotation); + + EXPECT_EQ(0x124 * PlayoutDelayLimits::kGranularityMs, + header.extension.playout_delay.min_ms); + EXPECT_EQ(0x876 * PlayoutDelayLimits::kGranularityMs, + header.extension.playout_delay.max_ms); + EXPECT_EQ(header.extension.stream_id, StreamId("rtx")); + EXPECT_EQ(header.extension.repaired_stream_id, StreamId("stream")); + + EXPECT_EQ(header.extension.csrcAudioLevels.numAudioLevels, 3); + EXPECT_EQ(header.extension.csrcAudioLevels.arrOfAudioLevels[0], 0x7f); + EXPECT_EQ(header.extension.csrcAudioLevels.arrOfAudioLevels[1], 0x01); + EXPECT_EQ(header.extension.csrcAudioLevels.arrOfAudioLevels[2], 0x10); +} + +TEST(RtpHeaderParser, ParseMalformedRsidExtensions) { + // clang-format off + const uint8_t kPacket[] = { + 0x90, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0xbe, 0xde, 0x00, 0x03, // Extension of size 3x32bit words. + 0xc2, '\0', 't', 'x', // empty RtpStreamId + 0xd5, 's', 't', 'r', '\0', 'a', 'm', // RepairedRtpStreamId + 0x00, // Padding to 32bit boundary. + }; + // clang-format on + ASSERT_EQ(sizeof(kPacket) % 4, 0u); + + RtpHeaderExtensionMap extensions; + extensions.Register<RtpStreamId>(0xc); + extensions.Register<RepairedRtpStreamId>(0xd); + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, &extensions)); + EXPECT_TRUE(header.extension.stream_id.empty()); + EXPECT_EQ(header.extension.repaired_stream_id, StreamId("str")); +} + +TEST(RtpHeaderParser, ParseWithCsrcsExtensionAndPadding) { + const uint8_t kPacketPaddingSize = 8; + const uint32_t kCsrcs[] = {0x34567890, 0x32435465}; + const size_t kPayloadSize = 7; + // clang-format off + const uint8_t kPacket[] = { + 0xb2, kPayloadType, 0x00, kSeqNum, + 0x65, 0x43, 0x12, 0x78, // kTimestamp. + 0x12, 0x34, 0x56, 0x78, // kSsrc. + 0x34, 0x56, 0x78, 0x90, // kCsrcs[0]. + 0x32, 0x43, 0x54, 0x65, // kCsrcs[1]. + 0xbe, 0xde, 0x00, 0x01, // Extension. + 0x12, 0x00, 0x56, 0xce, // TransmissionTimeOffset with id = 1. + 'p', 'a', 'y', 'l', 'o', 'a', 'd', + 'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize}; + // clang-format on + RtpHeaderExtensionMap extensions; + extensions.Register<TransmissionOffset>(1); + RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket)); + RTPHeader header; + + EXPECT_TRUE(parser.Parse(&header, &extensions)); + + EXPECT_EQ(kPayloadType, header.payloadType); + EXPECT_EQ(kSeqNum, header.sequenceNumber); + EXPECT_EQ(kTimestamp, header.timestamp); + EXPECT_EQ(kSsrc, header.ssrc); + EXPECT_THAT(make_tuple(header.arrOfCSRCs, header.numCSRCs), + ElementsAreArray(kCsrcs)); + EXPECT_EQ(kPacketPaddingSize, header.paddingLength); + EXPECT_THAT(sizeof(kPacket) - kPayloadSize - kPacketPaddingSize, + header.headerLength); + EXPECT_TRUE(header.extension.hasTransmissionTimeOffset); + EXPECT_EQ(0x56ce, header.extension.transmissionTimeOffset); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.cc new file mode 100644 index 0000000000..6ac280a61d --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.cc @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/time_util.h" + +#include <algorithm> + +#include "rtc_base/timeutils.h" + +namespace webrtc { +namespace { +// TODO(danilchap): Make generic, optimize and move to base. +inline int64_t DivideRoundToNearest(int64_t x, uint32_t y) { + // Callers ensure x is positive and x + y / 2 doesn't overflow. + return (x + y / 2) / y; +} + +int64_t NtpOffsetUs() { + constexpr int64_t kNtpJan1970Sec = 2208988800; + int64_t clock_time = rtc::TimeMicros(); + int64_t utc_time = rtc::TimeUTCMicros(); + return utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec; +} + +} // namespace + +NtpTime TimeMicrosToNtp(int64_t time_us) { + // Calculate the offset once. + static int64_t ntp_offset_us = NtpOffsetUs(); + + int64_t time_ntp_us = time_us + ntp_offset_us; + RTC_DCHECK_GE(time_ntp_us, 0); // Time before year 1900 is unsupported. + + // TODO(danilchap): Convert both seconds and fraction together using int128 + // when that type is easily available. + // Currently conversion is done separetly for seconds and fraction of a second + // to avoid overflow. + + // Convert seconds to uint32 through uint64 for well-defined cast. + // Wrap around (will happen in 2036) is expected for ntp time. + uint32_t ntp_seconds = + static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec); + + // Scale fractions of the second to ntp resolution. + constexpr int64_t kNtpInSecond = 1LL << 32; + int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec; + uint32_t ntp_fractions = + us_fractions * kNtpInSecond / rtc::kNumMicrosecsPerSec; + return NtpTime(ntp_seconds, ntp_fractions); +} + +uint32_t SaturatedUsToCompactNtp(int64_t us) { + constexpr uint32_t kMaxCompactNtp = 0xFFFFFFFF; + constexpr int kCompactNtpInSecond = 0x10000; + if (us <= 0) + return 0; + if (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, + rtc::kNumMicrosecsPerSec); +} + +int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval) { + // 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. + if (compact_ntp_interval > 0x80000000) + return 1; + // Convert to 64bit value to avoid multiplication overflow. + int64_t value = static_cast<int64_t>(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<int64_t>(ms, 1); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.h new file mode 100644 index 0000000000..3e7d1e29f1 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.h @@ -0,0 +1,55 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_ +#define MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_ + +#include <stdint.h> + +#include "system_wrappers/include/ntp_time.h" + +namespace webrtc { + +// Converts time obtained using rtc::TimeMicros to ntp format. +// TimeMicrosToNtp guarantees difference of the returned values matches +// difference of the passed values. +// As a result TimeMicrosToNtp(rtc::TimeMicros()) doesn't guarantte to match +// system time after first call. +NtpTime TimeMicrosToNtp(int64_t time_us); + +// Converts NTP timestamp to RTP timestamp. +inline uint32_t NtpToRtp(NtpTime ntp, uint32_t freq) { + uint32_t tmp = (static_cast<uint64_t>(ntp.fractions()) * freq) >> 32; + return ntp.seconds() * freq + tmp; +} + +// Helper function for compact ntp representation: +// RFC 3550, Section 4. Time Format. +// Wallclock time is represented using the timestamp format of +// the Network Time Protocol (NTP). +// ... +// In some fields where a more compact representation is +// appropriate, only the middle 32 bits are used; that is, the low 16 +// bits of the integer part and the high 16 bits of the fractional part. +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. +// Negative values converted to 0, Overlarge values converted to max uint32_t. +uint32_t SaturatedUsToCompactNtp(int64_t us); + +// Converts interval between compact ntp timestamps to milliseconds. +// 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); + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util_unittest.cc new file mode 100644 index 0000000000..cdf271284b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util_unittest.cc @@ -0,0 +1,132 @@ +/* + * 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. + */ +#include "modules/rtp_rtcp/source/time_util.h" + +#include "rtc_base/fakeclock.h" +#include "rtc_base/timeutils.h" +#include "system_wrappers/include/clock.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(TimeUtilTest, TimeMicrosToNtpMatchRealTimeClockInitially) { + Clock* legacy_clock = Clock::GetRealTimeClock(); + NtpTime before_legacy_time = TimeMicrosToNtp(rtc::TimeMicros()); + NtpTime legacy_time = legacy_clock->CurrentNtpTime(); + NtpTime after_legacy_time = TimeMicrosToNtp(rtc::TimeMicros()); + + // This test will fail once every 136 years, when NtpTime wraparound. + // More often than that, it will fail if system adjust ntp time while test + // is running. + // To mitigate ntp time adjustment and potentional different precisions of + // Clock and TimeMicrosToNtp, relax expectation by a millisecond. + EXPECT_GE(legacy_time.ToMs(), before_legacy_time.ToMs() - 1); + EXPECT_LE(legacy_time.ToMs(), after_legacy_time.ToMs() + 1); +} + +TEST(TimeUtilTest, TimeMicrosToNtpDoesntChangeBetweenRuns) { + rtc::ScopedFakeClock clock; + // TimeMicrosToNtp is not pure: it behave differently between different + // execution of the program, but should behave same during same execution. + const int64_t time_us = 12345; + clock.SetTimeMicros(2); + NtpTime time_ntp = TimeMicrosToNtp(time_us); + clock.SetTimeMicros(time_us); + EXPECT_EQ(TimeMicrosToNtp(time_us), time_ntp); + clock.SetTimeMicros(1000000); + EXPECT_EQ(TimeMicrosToNtp(time_us), time_ntp); +} + +TEST(TimeUtilTest, TimeMicrosToNtpKeepsIntervals) { + rtc::ScopedFakeClock clock; + NtpTime time_ntp1 = TimeMicrosToNtp(rtc::TimeMicros()); + clock.AdvanceTimeMicros(20000); + NtpTime time_ntp2 = TimeMicrosToNtp(rtc::TimeMicros()); + EXPECT_EQ(time_ntp2.ToMs() - time_ntp1.ToMs(), 20); +} + +TEST(TimeUtilTest, CompactNtp) { + const uint32_t kNtpSec = 0x12345678; + const uint32_t kNtpFrac = 0x23456789; + const NtpTime kNtp(kNtpSec, kNtpFrac); + const uint32_t kNtpMid = 0x56782345; + EXPECT_EQ(kNtpMid, CompactNtp(kNtp)); +} + +TEST(TimeUtilTest, CompactNtpRttToMs) { + 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); +} + +TEST(TimeUtilTest, CompactNtpRttToMsWithWrap) { + const NtpTime ntp1(0x1ffff, 0x23456); + const NtpTime ntp2(0x20000, 0x64335); + int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs(); + + // While ntp2 > ntp1, there compact ntp presentation happen to be opposite. + // That shouldn't be a problem as long as unsigned arithmetic is used. + ASSERT_GT(ntp2.ToMs(), ntp1.ToMs()); + 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); +} + +TEST(TimeUtilTest, CompactNtpRttToMsLarge) { + 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); +} + +TEST(TimeUtilTest, CompactNtpRttToMsNegative) { + 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); +} + +TEST(TimeUtilTest, SaturatedUsToCompactNtp) { + // Converts negative to zero. + EXPECT_EQ(SaturatedUsToCompactNtp(-1), 0u); + EXPECT_EQ(SaturatedUsToCompactNtp(0), 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); + // 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); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.cc new file mode 100644 index 0000000000..8aa4530211 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.cc @@ -0,0 +1,182 @@ +/* + * 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 "modules/rtp_rtcp/source/tmmbr_help.h" + +#include <algorithm> +#include <limits> + +#include "rtc_base/checks.h" + +namespace webrtc { +std::vector<rtcp::TmmbItem> TMMBRHelp::FindBoundingSet( + std::vector<rtcp::TmmbItem> candidates) { + // Filter out candidates with 0 bitrate. + for (auto it = candidates.begin(); it != candidates.end();) { + if (!it->bitrate_bps()) + it = candidates.erase(it); + else + ++it; + } + + if (candidates.size() <= 1) + return candidates; + + size_t num_candidates = candidates.size(); + + // 1. Sort by increasing packet overhead. + std::sort(candidates.begin(), candidates.end(), + [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) { + return lhs.packet_overhead() < rhs.packet_overhead(); + }); + + // 2. For tuples with same overhead, keep the one with the lowest bitrate. + for (auto it = candidates.begin(); it != candidates.end();) { + RTC_DCHECK(it->bitrate_bps()); + auto current_min = it; + auto next_it = it + 1; + // Use fact candidates are sorted by overhead, so candidates with same + // overhead are adjusted. + while (next_it != candidates.end() && + next_it->packet_overhead() == current_min->packet_overhead()) { + if (next_it->bitrate_bps() < current_min->bitrate_bps()) { + current_min->set_bitrate_bps(0); + current_min = next_it; + } else { + next_it->set_bitrate_bps(0); + } + ++next_it; + --num_candidates; + } + it = next_it; + } + + // 3. Select and remove tuple with lowest bitrate. + // (If more than 1, choose the one with highest overhead). + auto min_bitrate_it = candidates.end(); + for (auto it = candidates.begin(); it != candidates.end(); ++it) { + if (it->bitrate_bps()) { + min_bitrate_it = it; + break; + } + } + + for (auto it = min_bitrate_it; it != candidates.end(); ++it) { + if (it->bitrate_bps() && + it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) { + // Get min bitrate. + min_bitrate_it = it; + } + } + + std::vector<rtcp::TmmbItem> bounding_set; + bounding_set.reserve(num_candidates); + std::vector<float> intersection(num_candidates); + std::vector<float> max_packet_rate(num_candidates); + + // First member of selected list. + bounding_set.push_back(*min_bitrate_it); + intersection[0] = 0; + // Calculate its maximum packet rate (where its line crosses x-axis). + uint16_t packet_overhead = bounding_set.back().packet_overhead(); + if (packet_overhead == 0) { + // Avoid division by zero. + max_packet_rate[0] = std::numeric_limits<float>::max(); + } else { + max_packet_rate[0] = + bounding_set.back().bitrate_bps() / static_cast<float>(packet_overhead); + } + // Remove from candidate list. + min_bitrate_it->set_bitrate_bps(0); + --num_candidates; + + // 4. Discard from candidate list all tuple with lower overhead + // (next tuple must be steeper). + for (auto it = candidates.begin(); it != candidates.end(); ++it) { + if (it->bitrate_bps() && + it->packet_overhead() < bounding_set.front().packet_overhead()) { + it->set_bitrate_bps(0); + --num_candidates; + } + } + + bool get_new_candidate = true; + rtcp::TmmbItem cur_candidate; + while (num_candidates > 0) { + if (get_new_candidate) { + // 5. Remove first remaining tuple from candidate list. + for (auto it = candidates.begin(); it != candidates.end(); ++it) { + if (it->bitrate_bps()) { + cur_candidate = *it; + it->set_bitrate_bps(0); + break; + } + } + } + + // 6. Calculate packet rate and intersection of the current + // line with line of last tuple in selected list. + RTC_DCHECK_NE(cur_candidate.packet_overhead(), + bounding_set.back().packet_overhead()); + float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() - + bounding_set.back().bitrate_bps()) / + (cur_candidate.packet_overhead() - + bounding_set.back().packet_overhead()); + + // 7. If the packet rate is equal or lower than intersection of + // last tuple in selected list, + // remove last tuple in selected list & go back to step 6. + if (packet_rate <= intersection[bounding_set.size() - 1]) { + // Remove last tuple and goto step 6. + bounding_set.pop_back(); + get_new_candidate = false; + } else { + // 8. If packet rate is lower than maximum packet rate of + // last tuple in selected list, add current tuple to selected + // list. + if (packet_rate < max_packet_rate[bounding_set.size() - 1]) { + bounding_set.push_back(cur_candidate); + intersection[bounding_set.size() - 1] = packet_rate; + uint16_t packet_overhead = bounding_set.back().packet_overhead(); + RTC_DCHECK_NE(packet_overhead, 0); + max_packet_rate[bounding_set.size() - 1] = + bounding_set.back().bitrate_bps() / + static_cast<float>(packet_overhead); + } + --num_candidates; + get_new_candidate = true; + } + + // 9. Go back to step 5 if any tuple remains in candidate list. + } + RTC_DCHECK(!bounding_set.empty()); + return bounding_set; +} + +bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding, + uint32_t ssrc) { + for (const rtcp::TmmbItem& item : bounding) { + if (item.ssrc() == ssrc) { + return true; + } + } + return false; +} + +uint64_t TMMBRHelp::CalcMinBitrateBps( + const std::vector<rtcp::TmmbItem>& candidates) { + RTC_DCHECK(!candidates.empty()); + uint64_t min_bitrate_bps = std::numeric_limits<uint64_t>::max(); + for (const rtcp::TmmbItem& item : candidates) + if (item.bitrate_bps() < min_bitrate_bps) + min_bitrate_bps = item.bitrate_bps(); + return min_bitrate_bps; +} +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.h new file mode 100644 index 0000000000..46ce845507 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.h @@ -0,0 +1,33 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_TMMBR_HELP_H_ +#define MODULES_RTP_RTCP_SOURCE_TMMBR_HELP_H_ + +#include <vector> +#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class TMMBRHelp { + public: + static std::vector<rtcp::TmmbItem> FindBoundingSet( + std::vector<rtcp::TmmbItem> candidates); + + static bool IsOwner(const std::vector<rtcp::TmmbItem>& bounding, + uint32_t ssrc); + + static uint64_t CalcMinBitrateBps( + const std::vector<rtcp::TmmbItem>& candidates); +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_TMMBR_HELP_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc new file mode 100644 index 0000000000..8dc9752863 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc @@ -0,0 +1,244 @@ +/* + * 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 "modules/rtp_rtcp/source/ulpfec_generator.h" + +#include <memory> +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +namespace { + +constexpr size_t kRedForFecHeaderLength = 1; + +// This controls the maximum amount of excess overhead (actual - target) +// allowed in order to trigger EncodeFec(), before |params_.max_fec_frames| +// is reached. Overhead here is defined as relative to number of media packets. +constexpr int kMaxExcessOverhead = 50; // Q8. + +// This is the minimum number of media packets required (above some protection +// level) in order to trigger EncodeFec(), before |params_.max_fec_frames| is +// reached. +constexpr size_t kMinMediaPackets = 4; + +// Threshold on the received FEC protection level, above which we enforce at +// least |kMinMediaPackets| packets for the FEC code. Below this +// threshold |kMinMediaPackets| is set to default value of 1. +// +// The range is between 0 and 255, where 255 corresponds to 100% overhead +// (relative to the number of protected media packets). +constexpr uint8_t kHighProtectionThreshold = 80; + +// This threshold is used to adapt the |kMinMediaPackets| threshold, based +// on the average number of packets per frame seen so far. When there are few +// packets per frame (as given by this threshold), at least +// |kMinMediaPackets| + 1 packets are sent to the FEC code. +constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f; + +// At construction time, we don't know the SSRC that is used for the generated +// FEC packets, but we still need to give it to the ForwardErrorCorrection ctor +// to be used in the decoding. +// TODO(brandtr): Get rid of this awkwardness by splitting +// ForwardErrorCorrection in two objects -- one encoder and one decoder. +constexpr uint32_t kUnknownSsrc = 0; + +} // namespace + +RedPacket::RedPacket(size_t length) + : data_(new uint8_t[length]), length_(length), header_length_(0) {} + +void RedPacket::CreateHeader(const uint8_t* rtp_header, + size_t header_length, + int red_payload_type, + int payload_type) { + RTC_DCHECK_LE(header_length + kRedForFecHeaderLength, length_); + memcpy(data_.get(), rtp_header, header_length); + // Replace payload type. + data_[1] &= 0x80; + data_[1] += red_payload_type; + // Add RED header + // f-bit always 0 + data_[header_length] = static_cast<uint8_t>(payload_type); + header_length_ = header_length + kRedForFecHeaderLength; +} + +void RedPacket::SetSeqNum(int seq_num) { + RTC_DCHECK_GE(seq_num, 0); + RTC_DCHECK_LT(seq_num, 1 << 16); + + ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num); +} + +void RedPacket::AssignPayload(const uint8_t* payload, size_t length) { + RTC_DCHECK_LE(header_length_ + length, length_); + memcpy(data_.get() + header_length_, payload, length); +} + +void RedPacket::ClearMarkerBit() { + data_[1] &= 0x7F; +} + +uint8_t* RedPacket::data() const { + return data_.get(); +} + +size_t RedPacket::length() const { + return length_; +} + +UlpfecGenerator::UlpfecGenerator() + : UlpfecGenerator(ForwardErrorCorrection::CreateUlpfec(kUnknownSsrc)) {} + +UlpfecGenerator::UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec) + : fec_(std::move(fec)), + num_protected_frames_(0), + min_num_media_packets_(1) { + memset(¶ms_, 0, sizeof(params_)); + memset(&new_params_, 0, sizeof(new_params_)); +} + +UlpfecGenerator::~UlpfecGenerator() = default; + +void UlpfecGenerator::SetFecParameters(const FecProtectionParams& params) { + RTC_DCHECK_GE(params.fec_rate, 0); + RTC_DCHECK_LE(params.fec_rate, 255); + // Store the new params and apply them for the next set of FEC packets being + // produced. + new_params_ = params; + if (params.fec_rate > kHighProtectionThreshold) { + min_num_media_packets_ = kMinMediaPackets; + } else { + min_num_media_packets_ = 1; + } +} + +int UlpfecGenerator::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer, + size_t payload_length, + size_t rtp_header_length) { + RTC_DCHECK(generated_fec_packets_.empty()); + if (media_packets_.empty()) { + params_ = new_params_; + } + bool complete_frame = false; + const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false; + if (media_packets_.size() < kUlpfecMaxMediaPackets) { + // Our packet masks can only protect up to |kUlpfecMaxMediaPackets| packets. + std::unique_ptr<ForwardErrorCorrection::Packet> packet( + new ForwardErrorCorrection::Packet()); + packet->length = payload_length + rtp_header_length; + memcpy(packet->data, data_buffer, packet->length); + media_packets_.push_back(std::move(packet)); + } + if (marker_bit) { + ++num_protected_frames_; + complete_frame = true; + } + // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as: + // (1) the excess overhead (actual overhead - requested/target overhead) is + // less than |kMaxExcessOverhead|, and + // (2) at least |min_num_media_packets_| media packets is reached. + if (complete_frame && + (num_protected_frames_ == params_.max_fec_frames || + (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) { + // We are not using Unequal Protection feature of the parity erasure code. + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + int ret = fec_->EncodeFec(media_packets_, params_.fec_rate, + kNumImportantPackets, kUseUnequalProtection, + params_.fec_mask_type, &generated_fec_packets_); + if (generated_fec_packets_.empty()) { + ResetState(); + } + return ret; + } + return 0; +} + +bool UlpfecGenerator::ExcessOverheadBelowMax() const { + return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead); +} + +bool UlpfecGenerator::MinimumMediaPacketsReached() const { + float average_num_packets_per_frame = + static_cast<float>(media_packets_.size()) / num_protected_frames_; + int num_media_packets = static_cast<int>(media_packets_.size()); + if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) { + return num_media_packets >= min_num_media_packets_; + } else { + // For larger rates (more packets/frame), increase the threshold. + // TODO(brandtr): Investigate what impact this adaptation has. + return num_media_packets >= min_num_media_packets_ + 1; + } +} + +bool UlpfecGenerator::FecAvailable() const { + return !generated_fec_packets_.empty(); +} + +size_t UlpfecGenerator::NumAvailableFecPackets() const { + return generated_fec_packets_.size(); +} + +size_t UlpfecGenerator::MaxPacketOverhead() const { + return fec_->MaxPacketOverhead(); +} + +std::vector<std::unique_ptr<RedPacket>> UlpfecGenerator::GetUlpfecPacketsAsRed( + int red_payload_type, + int ulpfec_payload_type, + uint16_t first_seq_num, + size_t rtp_header_length) { + std::vector<std::unique_ptr<RedPacket>> red_packets; + red_packets.reserve(generated_fec_packets_.size()); + RTC_DCHECK(!media_packets_.empty()); + ForwardErrorCorrection::Packet* last_media_packet = + media_packets_.back().get(); + uint16_t seq_num = first_seq_num; + for (const auto& fec_packet : generated_fec_packets_) { + // Wrap FEC packet (including FEC headers) in a RED packet. Since the + // FEC packets in |generated_fec_packets_| don't have RTP headers, we + // reuse the header from the last media packet. + std::unique_ptr<RedPacket> red_packet(new RedPacket( + fec_packet->length + kRedForFecHeaderLength + rtp_header_length)); + red_packet->CreateHeader(last_media_packet->data, rtp_header_length, + red_payload_type, ulpfec_payload_type); + red_packet->SetSeqNum(seq_num++); + red_packet->ClearMarkerBit(); + red_packet->AssignPayload(fec_packet->data, fec_packet->length); + red_packets.push_back(std::move(red_packet)); + } + + ResetState(); + + return red_packets; +} + +int UlpfecGenerator::Overhead() const { + RTC_DCHECK(!media_packets_.empty()); + int num_fec_packets = + fec_->NumFecPackets(media_packets_.size(), params_.fec_rate); + // Return the overhead in Q8. + return (num_fec_packets << 8) / media_packets_.size(); +} + +void UlpfecGenerator::ResetState() { + media_packets_.clear(); + generated_fec_packets_.clear(); + num_protected_frames_ = 0; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h new file mode 100644 index 0000000000..3de7ae2986 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h @@ -0,0 +1,110 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_ULPFEC_GENERATOR_H_ +#define MODULES_RTP_RTCP_SOURCE_ULPFEC_GENERATOR_H_ + +#include <list> +#include <memory> +#include <vector> + +#include "modules/rtp_rtcp/source/forward_error_correction.h" + +namespace webrtc { + +class FlexfecSender; + +class RedPacket { + public: + explicit RedPacket(size_t length); + + void CreateHeader(const uint8_t* rtp_header, + size_t header_length, + int red_payload_type, + int payload_type); + void SetSeqNum(int seq_num); + void AssignPayload(const uint8_t* payload, size_t length); + void ClearMarkerBit(); + uint8_t* data() const; + size_t length() const; + + private: + std::unique_ptr<uint8_t[]> data_; + size_t length_; + size_t header_length_; +}; + +class UlpfecGenerator { + friend class FlexfecSender; + + public: + UlpfecGenerator(); + ~UlpfecGenerator(); + + void SetFecParameters(const FecProtectionParams& params); + + // Adds a media packet to the internal buffer. When enough media packets + // have been added, the FEC packets are generated and stored internally. + // These FEC packets are then obtained by calling GetFecPacketsAsRed(). + int AddRtpPacketAndGenerateFec(const uint8_t* data_buffer, + size_t payload_length, + size_t rtp_header_length); + + // Returns true if there are generated FEC packets available. + bool FecAvailable() const; + + size_t NumAvailableFecPackets() const; + + // Returns the overhead, per packet, for FEC (and possibly RED). + size_t MaxPacketOverhead() const; + + // Returns generated FEC packets with RED headers added. + std::vector<std::unique_ptr<RedPacket>> GetUlpfecPacketsAsRed( + int red_payload_type, + int ulpfec_payload_type, + uint16_t first_seq_num, + size_t rtp_header_length); + + private: + explicit UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec); + + // Overhead is defined as relative to the number of media packets, and not + // relative to total number of packets. This definition is inherited from the + // protection factor produced by video_coding module and how the FEC + // generation is implemented. + int Overhead() const; + + // Returns true if the excess overhead (actual - target) for the FEC is below + // the amount |kMaxExcessOverhead|. This effects the lower protection level + // cases and low number of media packets/frame. The target overhead is given + // by |params_.fec_rate|, and is only achievable in the limit of large number + // of media packets. + bool ExcessOverheadBelowMax() const; + + // Returns true if the number of added media packets is at least + // |min_num_media_packets_|. This condition tries to capture the effect + // that, for the same amount of protection/overhead, longer codes + // (e.g. (2k,2m) vs (k,m)) are generally more effective at recovering losses. + bool MinimumMediaPacketsReached() const; + + void ResetState(); + + std::unique_ptr<ForwardErrorCorrection> fec_; + ForwardErrorCorrection::PacketList media_packets_; + std::list<ForwardErrorCorrection::Packet*> generated_fec_packets_; + int num_protected_frames_; + int min_num_media_packets_; + FecProtectionParams params_; + FecProtectionParams new_params_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_ULPFEC_GENERATOR_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc new file mode 100644 index 0000000000..6586d0dc88 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc @@ -0,0 +1,170 @@ +/* + * 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 <list> +#include <memory> +#include <utility> +#include <vector> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/fec_test_helper.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/ulpfec_generator.h" +#include "rtc_base/basictypes.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { +using test::fec::AugmentedPacket; +using test::fec::AugmentedPacketGenerator; + +constexpr int kFecPayloadType = 96; +constexpr int kRedPayloadType = 97; +constexpr uint32_t kMediaSsrc = 835424; +} // namespace + +void VerifyHeader(uint16_t seq_num, + uint32_t timestamp, + int red_payload_type, + int fec_payload_type, + RedPacket* packet, + bool marker_bit) { + EXPECT_GT(packet->length(), kRtpHeaderSize); + EXPECT_TRUE(packet->data() != NULL); + uint8_t* data = packet->data(); + // Marker bit not set. + EXPECT_EQ(marker_bit ? 0x80 : 0, data[1] & 0x80); + EXPECT_EQ(red_payload_type, data[1] & 0x7F); + EXPECT_EQ(seq_num, (data[2] << 8) + data[3]); + uint32_t parsed_timestamp = + (data[4] << 24) + (data[5] << 16) + (data[6] << 8) + data[7]; + EXPECT_EQ(timestamp, parsed_timestamp); + EXPECT_EQ(static_cast<uint8_t>(fec_payload_type), data[kRtpHeaderSize]); +} + +class UlpfecGeneratorTest : public ::testing::Test { + protected: + UlpfecGeneratorTest() : packet_generator_(kMediaSsrc) {} + + UlpfecGenerator ulpfec_generator_; + AugmentedPacketGenerator packet_generator_; +}; + +// Verifies bug found via fuzzing, where a gap in the packet sequence caused us +// to move past the end of the current FEC packet mask byte without moving to +// the next byte. That likely caused us to repeatedly read from the same byte, +// and if that byte didn't protect packets we would generate empty FEC. +TEST_F(UlpfecGeneratorTest, NoEmptyFecWithSeqNumGaps) { + struct Packet { + size_t header_size; + size_t payload_size; + uint16_t seq_num; + bool marker_bit; + }; + std::vector<Packet> protected_packets; + protected_packets.push_back({15, 3, 41, 0}); + protected_packets.push_back({14, 1, 43, 0}); + protected_packets.push_back({19, 0, 48, 0}); + protected_packets.push_back({19, 0, 50, 0}); + protected_packets.push_back({14, 3, 51, 0}); + protected_packets.push_back({13, 8, 52, 0}); + protected_packets.push_back({19, 2, 53, 0}); + protected_packets.push_back({12, 3, 54, 0}); + protected_packets.push_back({21, 0, 55, 0}); + protected_packets.push_back({13, 3, 57, 1}); + FecProtectionParams params = {117, 3, kFecMaskBursty}; + ulpfec_generator_.SetFecParameters(params); + uint8_t packet[28] = {0}; + for (Packet p : protected_packets) { + if (p.marker_bit) { + packet[1] |= 0x80; + } else { + packet[1] &= ~0x80; + } + ByteWriter<uint16_t>::WriteBigEndian(&packet[2], p.seq_num); + ulpfec_generator_.AddRtpPacketAndGenerateFec(packet, p.payload_size, + p.header_size); + size_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets(); + if (num_fec_packets > 0) { + std::vector<std::unique_ptr<RedPacket>> fec_packets = + ulpfec_generator_.GetUlpfecPacketsAsRed( + kRedPayloadType, kFecPayloadType, 100, p.header_size); + EXPECT_EQ(num_fec_packets, fec_packets.size()); + } + } +} + +TEST_F(UlpfecGeneratorTest, OneFrameFec) { + // The number of media packets (|kNumPackets|), number of frames (one for + // this test), and the protection factor (|params->fec_rate|) are set to make + // sure the conditions for generating FEC are satisfied. This means: + // (1) protection factor is high enough so that actual overhead over 1 frame + // of packets is within |kMaxExcessOverhead|, and (2) the total number of + // media packets for 1 frame is at least |minimum_media_packets_fec_|. + constexpr size_t kNumPackets = 4; + FecProtectionParams params = {15, 3, kFecMaskRandom}; + packet_generator_.NewFrame(kNumPackets); + ulpfec_generator_.SetFecParameters(params); // Expecting one FEC packet. + uint32_t last_timestamp = 0; + for (size_t i = 0; i < kNumPackets; ++i) { + std::unique_ptr<AugmentedPacket> packet = + packet_generator_.NextPacket(i, 10); + EXPECT_EQ(0, ulpfec_generator_.AddRtpPacketAndGenerateFec( + packet->data, packet->length, kRtpHeaderSize)); + last_timestamp = packet->header.header.timestamp; + } + EXPECT_TRUE(ulpfec_generator_.FecAvailable()); + uint16_t seq_num = packet_generator_.NextPacketSeqNum(); + std::vector<std::unique_ptr<RedPacket>> red_packets = + ulpfec_generator_.GetUlpfecPacketsAsRed(kRedPayloadType, kFecPayloadType, + seq_num, kRtpHeaderSize); + EXPECT_FALSE(ulpfec_generator_.FecAvailable()); + ASSERT_EQ(1u, red_packets.size()); + VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType, + red_packets.front().get(), false); +} + +TEST_F(UlpfecGeneratorTest, TwoFrameFec) { + // The number of media packets/frame (|kNumPackets|), the number of frames + // (|kNumFrames|), and the protection factor (|params->fec_rate|) are set to + // make sure the conditions for generating FEC are satisfied. This means: + // (1) protection factor is high enough so that actual overhead over + // |kNumFrames| is within |kMaxExcessOverhead|, and (2) the total number of + // media packets for |kNumFrames| frames is at least + // |minimum_media_packets_fec_|. + constexpr size_t kNumPackets = 2; + constexpr size_t kNumFrames = 2; + + FecProtectionParams params = {15, 3, kFecMaskRandom}; + ulpfec_generator_.SetFecParameters(params); // Expecting one FEC packet. + uint32_t last_timestamp = 0; + for (size_t i = 0; i < kNumFrames; ++i) { + packet_generator_.NewFrame(kNumPackets); + for (size_t j = 0; j < kNumPackets; ++j) { + std::unique_ptr<AugmentedPacket> packet = + packet_generator_.NextPacket(i * kNumPackets + j, 10); + EXPECT_EQ(0, ulpfec_generator_.AddRtpPacketAndGenerateFec( + packet->data, packet->length, kRtpHeaderSize)); + last_timestamp = packet->header.header.timestamp; + } + } + EXPECT_TRUE(ulpfec_generator_.FecAvailable()); + uint16_t seq_num = packet_generator_.NextPacketSeqNum(); + std::vector<std::unique_ptr<RedPacket>> red_packets = + ulpfec_generator_.GetUlpfecPacketsAsRed(kRedPayloadType, kFecPayloadType, + seq_num, kRtpHeaderSize); + EXPECT_FALSE(ulpfec_generator_.FecAvailable()); + ASSERT_EQ(1u, red_packets.size()); + VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType, + red_packets.front().get(), false); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc new file mode 100644 index 0000000000..c54d3cdd8f --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016 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/rtp_rtcp/source/ulpfec_header_reader_writer.h" + +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +namespace { + +// Maximum number of media packets that can be protected in one batch. +constexpr size_t kMaxMediaPackets = 48; + +// Maximum number of FEC packets stored inside ForwardErrorCorrection. +constexpr size_t kMaxFecPackets = kMaxMediaPackets; + +// FEC Level 0 header size in bytes. +constexpr size_t kFecLevel0HeaderSize = 10; + +// FEC Level 1 (ULP) header size in bytes (L bit is set). +constexpr size_t kFecLevel1HeaderSizeLBitSet = 2 + kUlpfecPacketMaskSizeLBitSet; + +// FEC Level 1 (ULP) header size in bytes (L bit is cleared). +constexpr size_t kFecLevel1HeaderSizeLBitClear = + 2 + kUlpfecPacketMaskSizeLBitClear; + +constexpr size_t kPacketMaskOffset = kFecLevel0HeaderSize + 2; + +size_t UlpfecHeaderSize(size_t packet_mask_size) { + RTC_DCHECK_LE(packet_mask_size, kUlpfecPacketMaskSizeLBitSet); + if (packet_mask_size <= kUlpfecPacketMaskSizeLBitClear) { + return kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitClear; + } else { + return kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitSet; + } +} + +} // namespace + +UlpfecHeaderReader::UlpfecHeaderReader() + : FecHeaderReader(kMaxMediaPackets, kMaxFecPackets) {} + +UlpfecHeaderReader::~UlpfecHeaderReader() = default; + +bool UlpfecHeaderReader::ReadFecHeader( + ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const { + bool l_bit = (fec_packet->pkt->data[0] & 0x40) != 0u; + size_t packet_mask_size = + l_bit ? kUlpfecPacketMaskSizeLBitSet : kUlpfecPacketMaskSizeLBitClear; + fec_packet->fec_header_size = UlpfecHeaderSize(packet_mask_size); + uint16_t seq_num_base = + ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[2]); + fec_packet->protected_ssrc = fec_packet->ssrc; // Due to RED. + fec_packet->seq_num_base = seq_num_base; + fec_packet->packet_mask_offset = kPacketMaskOffset; + fec_packet->packet_mask_size = packet_mask_size; + fec_packet->protection_length = + ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[10]); + + // Store length recovery field in temporary location in header. + // This makes the header "compatible" with the corresponding + // FlexFEC location of the length recovery field, thus simplifying + // the XORing operations. + memcpy(&fec_packet->pkt->data[2], &fec_packet->pkt->data[8], 2); + + return true; +} + +UlpfecHeaderWriter::UlpfecHeaderWriter() + : FecHeaderWriter(kMaxMediaPackets, + kMaxFecPackets, + kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitSet) {} + +UlpfecHeaderWriter::~UlpfecHeaderWriter() = default; + +// TODO(brandtr): Consider updating this implementation (which actually +// returns a bound on the sequence number spread), if logic is added to +// UlpfecHeaderWriter::FinalizeFecHeader to truncate packet masks which end +// in a string of zeroes. (Similar to how it is done in the FlexFEC case.) +size_t UlpfecHeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask, + size_t packet_mask_size) const { + return packet_mask_size; +} + +size_t UlpfecHeaderWriter::FecHeaderSize(size_t packet_mask_size) const { + return UlpfecHeaderSize(packet_mask_size); +} + +void UlpfecHeaderWriter::FinalizeFecHeader( + uint32_t /* media_ssrc */, + uint16_t seq_num_base, + const uint8_t* packet_mask, + size_t packet_mask_size, + ForwardErrorCorrection::Packet* fec_packet) const { + // Set E bit to zero. + fec_packet->data[0] &= 0x7f; + // Set L bit based on packet mask size. (Note that the packet mask + // can only take on two discrete values.) + bool l_bit = (packet_mask_size == kUlpfecPacketMaskSizeLBitSet); + if (l_bit) { + fec_packet->data[0] |= 0x40; // Set the L bit. + } else { + RTC_DCHECK_EQ(packet_mask_size, kUlpfecPacketMaskSizeLBitClear); + fec_packet->data[0] &= 0xbf; // Clear the L bit. + } + // Copy length recovery field from temporary location. + memcpy(&fec_packet->data[8], &fec_packet->data[2], 2); + // Write sequence number base. + ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2], seq_num_base); + // Protection length is set to entire packet. (This is not + // required in general.) + const size_t fec_header_size = FecHeaderSize(packet_mask_size); + ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[10], + fec_packet->length - fec_header_size); + // Copy the packet mask. + memcpy(&fec_packet->data[12], packet_mask, packet_mask_size); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h new file mode 100644 index 0000000000..ac9fcc171b --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 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_RTP_RTCP_SOURCE_ULPFEC_HEADER_READER_WRITER_H_ +#define MODULES_RTP_RTCP_SOURCE_ULPFEC_HEADER_READER_WRITER_H_ + +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "rtc_base/basictypes.h" + +namespace webrtc { + +// FEC Level 0 Header, 10 bytes. +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |E|L|P|X| CC |M| PT recovery | SN base | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | TS recovery | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | length recovery | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// FEC Level 1 Header, 4 bytes (L = 0) or 8 bytes (L = 1). +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Protection Length | mask | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | mask cont. (present only when L = 1) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +class UlpfecHeaderReader : public FecHeaderReader { + public: + UlpfecHeaderReader(); + ~UlpfecHeaderReader() override; + + bool ReadFecHeader( + ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override; +}; + +class UlpfecHeaderWriter : public FecHeaderWriter { + public: + UlpfecHeaderWriter(); + ~UlpfecHeaderWriter() override; + + size_t MinPacketMaskSize(const uint8_t* packet_mask, + size_t packet_mask_size) const override; + + size_t FecHeaderSize(size_t packet_mask_row_size) const override; + + void FinalizeFecHeader( + uint32_t media_ssrc, // Unused by ULPFEC. + uint16_t seq_num_base, + const uint8_t* packet_mask, + size_t packet_mask_size, + ForwardErrorCorrection::Packet* fec_packet) const override; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_ULPFEC_HEADER_READER_WRITER_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc new file mode 100644 index 0000000000..9eaaf89b44 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2016 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 <string.h> + +#include <memory> +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h" +#include "rtc_base/basictypes.h" +#include "rtc_base/checks.h" +#include "rtc_base/random.h" +#include "rtc_base/scoped_ref_ptr.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +using Packet = ForwardErrorCorrection::Packet; +using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket; + +constexpr uint32_t kMediaSsrc = 1254983; +constexpr uint16_t kMediaStartSeqNum = 825; +constexpr size_t kMediaPacketLength = 1234; + +constexpr size_t kUlpfecHeaderSizeLBitClear = 14; +constexpr size_t kUlpfecHeaderSizeLBitSet = 18; +constexpr size_t kUlpfecPacketMaskOffset = 12; + +std::unique_ptr<uint8_t[]> GeneratePacketMask(size_t packet_mask_size, + uint64_t seed) { + Random random(seed); + std::unique_ptr<uint8_t[]> packet_mask(new uint8_t[packet_mask_size]); + for (size_t i = 0; i < packet_mask_size; ++i) { + packet_mask[i] = random.Rand<uint8_t>(); + } + return packet_mask; +} + +std::unique_ptr<Packet> WriteHeader(const uint8_t* packet_mask, + size_t packet_mask_size) { + UlpfecHeaderWriter writer; + std::unique_ptr<Packet> written_packet(new Packet()); + written_packet->length = kMediaPacketLength; + for (size_t i = 0; i < written_packet->length; ++i) { + written_packet->data[i] = i; // Actual content doesn't matter. + } + writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask, + packet_mask_size, written_packet.get()); + return written_packet; +} + +std::unique_ptr<ReceivedFecPacket> ReadHeader(const Packet& written_packet) { + UlpfecHeaderReader reader; + std::unique_ptr<ReceivedFecPacket> read_packet(new ReceivedFecPacket()); + read_packet->ssrc = kMediaSsrc; + read_packet->pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(read_packet->pkt->data, written_packet.data, written_packet.length); + read_packet->pkt->length = written_packet.length; + EXPECT_TRUE(reader.ReadFecHeader(read_packet.get())); + return read_packet; +} + +void VerifyHeaders(size_t expected_fec_header_size, + const uint8_t* expected_packet_mask, + size_t expected_packet_mask_size, + const Packet& written_packet, + const ReceivedFecPacket& read_packet) { + EXPECT_EQ(kMediaSsrc, read_packet.ssrc); + EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size); + EXPECT_EQ(kMediaSsrc, read_packet.protected_ssrc); + EXPECT_EQ(kMediaStartSeqNum, read_packet.seq_num_base); + EXPECT_EQ(kUlpfecPacketMaskOffset, read_packet.packet_mask_offset); + ASSERT_EQ(expected_packet_mask_size, read_packet.packet_mask_size); + EXPECT_EQ(written_packet.length - expected_fec_header_size, + read_packet.protection_length); + EXPECT_EQ(0, memcmp(expected_packet_mask, + &read_packet.pkt->data[read_packet.packet_mask_offset], + read_packet.packet_mask_size)); + // Verify that the call to ReadFecHeader did not tamper with the payload. + EXPECT_EQ(0, memcmp(&written_packet.data[expected_fec_header_size], + &read_packet.pkt->data[expected_fec_header_size], + written_packet.length - expected_fec_header_size)); +} + +} // namespace + +TEST(UlpfecHeaderReaderTest, ReadsSmallHeader) { + const uint8_t packet[] = { + 0x00, 0x12, 0xab, 0xcd, // L bit clear, "random" payload type and SN base + 0x12, 0x34, 0x56, 0x78, // "random" TS recovery + 0xab, 0xcd, 0x11, 0x22, // "random" length recovery and protection length + 0x33, 0x44, // "random" packet mask + 0x00, 0x00, 0x00, 0x00 // payload + }; + const size_t packet_length = sizeof(packet); + ReceivedFecPacket read_packet; + read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(read_packet.pkt->data, packet, packet_length); + read_packet.pkt->length = packet_length; + + UlpfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + EXPECT_EQ(14U, read_packet.fec_header_size); + EXPECT_EQ(0xabcdU, read_packet.seq_num_base); + EXPECT_EQ(12U, read_packet.packet_mask_offset); + EXPECT_EQ(2U, read_packet.packet_mask_size); + EXPECT_EQ(0x1122U, read_packet.protection_length); +} + +TEST(UlpfecHeaderReaderTest, ReadsLargeHeader) { + const uint8_t packet[] = { + 0x40, 0x12, 0xab, 0xcd, // L bit set, "random" payload type and SN base + 0x12, 0x34, 0x56, 0x78, // "random" TS recovery + 0xab, 0xcd, 0x11, 0x22, // "random" length recovery and protection length + 0x33, 0x44, 0x55, 0x66, // "random" packet mask + 0x77, 0x88, // + 0x00, 0x00, 0x00, 0x00 // payload + }; + const size_t packet_length = sizeof(packet); + ReceivedFecPacket read_packet; + read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet()); + memcpy(read_packet.pkt->data, packet, packet_length); + read_packet.pkt->length = packet_length; + + UlpfecHeaderReader reader; + EXPECT_TRUE(reader.ReadFecHeader(&read_packet)); + + EXPECT_EQ(18U, read_packet.fec_header_size); + EXPECT_EQ(0xabcdU, read_packet.seq_num_base); + EXPECT_EQ(12U, read_packet.packet_mask_offset); + EXPECT_EQ(6U, read_packet.packet_mask_size); + EXPECT_EQ(0x1122U, read_packet.protection_length); +} + +TEST(UlpfecHeaderWriterTest, FinalizesSmallHeader) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + Packet written_packet; + written_packet.length = kMediaPacketLength; + for (size_t i = 0; i < written_packet.length; ++i) { + written_packet.data[i] = i; + } + + UlpfecHeaderWriter writer; + writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask.get(), + packet_mask_size, &written_packet); + + const uint8_t* packet = written_packet.data; + EXPECT_EQ(0x00, packet[0] & 0x80); // E bit. + EXPECT_EQ(0x00, packet[0] & 0x40); // L bit. + EXPECT_EQ(kMediaStartSeqNum, ByteReader<uint16_t>::ReadBigEndian(packet + 2)); + EXPECT_EQ( + static_cast<uint16_t>(kMediaPacketLength - kUlpfecHeaderSizeLBitClear), + ByteReader<uint16_t>::ReadBigEndian(packet + 10)); + EXPECT_EQ(0, memcmp(packet + kUlpfecPacketMaskOffset, packet_mask.get(), + packet_mask_size)); +} + +TEST(UlpfecHeaderWriterTest, FinalizesLargeHeader) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + Packet written_packet; + written_packet.length = kMediaPacketLength; + for (size_t i = 0; i < written_packet.length; ++i) { + written_packet.data[i] = i; + } + + UlpfecHeaderWriter writer; + writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask.get(), + packet_mask_size, &written_packet); + + const uint8_t* packet = written_packet.data; + EXPECT_EQ(0x00, packet[0] & 0x80); // E bit. + EXPECT_EQ(0x40, packet[0] & 0x40); // L bit. + EXPECT_EQ(kMediaStartSeqNum, ByteReader<uint16_t>::ReadBigEndian(packet + 2)); + EXPECT_EQ( + static_cast<uint16_t>(kMediaPacketLength - kUlpfecHeaderSizeLBitSet), + ByteReader<uint16_t>::ReadBigEndian(packet + 10)); + EXPECT_EQ(0, memcmp(packet + kUlpfecPacketMaskOffset, packet_mask.get(), + packet_mask_size)); +} + +TEST(UlpfecHeaderWriterTest, CalculateSmallHeaderSize) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + + UlpfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kUlpfecPacketMaskSizeLBitClear, min_packet_mask_size); + EXPECT_EQ(kUlpfecHeaderSizeLBitClear, + writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(UlpfecHeaderWriterTest, CalculateLargeHeaderSize) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + + UlpfecHeaderWriter writer; + size_t min_packet_mask_size = + writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size); + + EXPECT_EQ(kUlpfecPacketMaskSizeLBitSet, min_packet_mask_size); + EXPECT_EQ(kUlpfecHeaderSizeLBitSet, + writer.FecHeaderSize(min_packet_mask_size)); +} + +TEST(UlpfecHeaderReaderWriterTest, WriteAndReadSmallHeader) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyHeaders(kUlpfecHeaderSizeLBitClear, packet_mask.get(), packet_mask_size, + *written_packet, *read_packet); +} + +TEST(UlpfecHeaderReaderWriterTest, WriteAndReadLargeHeader) { + const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet; + auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd); + + auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size); + auto read_packet = ReadHeader(*written_packet); + + VerifyHeaders(kUlpfecHeaderSizeLBitSet, packet_mask.get(), packet_mask_size, + *written_packet, *read_packet); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc new file mode 100644 index 0000000000..65d17ccf8c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc @@ -0,0 +1,260 @@ +/* + * 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 "modules/rtp_rtcp/source/ulpfec_receiver_impl.h" + +#include <memory> +#include <utility> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_receiver_video.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +UlpfecReceiver* UlpfecReceiver::Create(uint32_t ssrc, + RecoveredPacketReceiver* callback) { + return new UlpfecReceiverImpl(ssrc, callback); +} + +UlpfecReceiverImpl::UlpfecReceiverImpl(uint32_t ssrc, + RecoveredPacketReceiver* callback) + : ssrc_(ssrc), + recovered_packet_callback_(callback), + fec_(ForwardErrorCorrection::CreateUlpfec(ssrc_)) {} + +UlpfecReceiverImpl::~UlpfecReceiverImpl() { + received_packets_.clear(); + fec_->ResetState(&recovered_packets_); +} + +FecPacketCounter UlpfecReceiverImpl::GetPacketCounter() const { + rtc::CritScope cs(&crit_sect_); + return packet_counter_; +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |F| block PT | timestamp offset | block length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// +// RFC 2198 RTP Payload for Redundant Audio Data September 1997 +// +// The bits in the header are specified as follows: +// +// F: 1 bit First bit in header indicates whether another header block +// follows. If 1 further header blocks follow, if 0 this is the +// last header block. +// If 0 there is only 1 byte RED header +// +// block PT: 7 bits RTP payload type for this block. +// +// timestamp offset: 14 bits Unsigned offset of timestamp of this block +// relative to timestamp given in RTP header. The use of an unsigned +// offset implies that redundant data must be sent after the primary +// data, and is hence a time to be subtracted from the current +// timestamp to determine the timestamp of the data for which this +// block is the redundancy. +// +// block length: 10 bits Length in bytes of the corresponding data +// block excluding header. + +int32_t UlpfecReceiverImpl::AddReceivedRedPacket( + const RTPHeader& header, + const uint8_t* incoming_rtp_packet, + size_t packet_length, + uint8_t ulpfec_payload_type) { + if (header.ssrc != ssrc_) { + RTC_LOG(LS_WARNING) + << "Received RED packet with different SSRC than expected; dropping."; + return -1; + } + if (packet_length > IP_PACKET_SIZE) { + RTC_LOG(LS_WARNING) << "Received RED packet with length exceeds maximum IP " + "packet size; dropping."; + return -1; + } + + rtc::CritScope cs(&crit_sect_); + + uint8_t red_header_length = 1; + size_t payload_data_length = packet_length - header.headerLength; + + if (payload_data_length == 0) { + RTC_LOG(LS_WARNING) << "Corrupt/truncated FEC packet."; + return -1; + } + + // Remove RED header of incoming packet and store as a virtual RTP packet. + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet( + new ForwardErrorCorrection::ReceivedPacket()); + received_packet->pkt = new ForwardErrorCorrection::Packet(); + + // Get payload type from RED header and sequence number from RTP header. + uint8_t payload_type = incoming_rtp_packet[header.headerLength] & 0x7f; + received_packet->is_fec = payload_type == ulpfec_payload_type; + received_packet->ssrc = header.ssrc; + received_packet->seq_num = header.sequenceNumber; + + uint16_t block_length = 0; + if (incoming_rtp_packet[header.headerLength] & 0x80) { + // f bit set in RED header, i.e. there are more than one RED header blocks. + red_header_length = 4; + if (payload_data_length < red_header_length + 1u) { + RTC_LOG(LS_WARNING) << "Corrupt/truncated FEC packet."; + return -1; + } + + uint16_t timestamp_offset = incoming_rtp_packet[header.headerLength + 1] + << 8; + timestamp_offset += incoming_rtp_packet[header.headerLength + 2]; + timestamp_offset = timestamp_offset >> 2; + if (timestamp_offset != 0) { + RTC_LOG(LS_WARNING) << "Corrupt payload found."; + return -1; + } + + block_length = (0x3 & incoming_rtp_packet[header.headerLength + 2]) << 8; + block_length += incoming_rtp_packet[header.headerLength + 3]; + + // Check next RED header block. + if (incoming_rtp_packet[header.headerLength + 4] & 0x80) { + RTC_LOG(LS_WARNING) << "More than 2 blocks in packet not supported."; + return -1; + } + // Check that the packet is long enough to contain data in the following + // block. + if (block_length > payload_data_length - (red_header_length + 1)) { + RTC_LOG(LS_WARNING) << "Block length longer than packet."; + return -1; + } + } + ++packet_counter_.num_packets; + if (packet_counter_.first_packet_time_ms == -1) { + packet_counter_.first_packet_time_ms = + Clock::GetRealTimeClock()->TimeInMilliseconds(); + } + + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> + second_received_packet; + if (block_length > 0) { + // Handle block length, split into two packets. + red_header_length = 5; + + // Copy RTP header. + memcpy(received_packet->pkt->data, incoming_rtp_packet, + header.headerLength); + + // Set payload type. + received_packet->pkt->data[1] &= 0x80; // Reset RED payload type. + received_packet->pkt->data[1] += payload_type; // Set media payload type. + + // Copy payload data. + memcpy(received_packet->pkt->data + header.headerLength, + incoming_rtp_packet + header.headerLength + red_header_length, + block_length); + received_packet->pkt->length = block_length; + + second_received_packet.reset(new ForwardErrorCorrection::ReceivedPacket); + second_received_packet->pkt = new ForwardErrorCorrection::Packet; + + second_received_packet->is_fec = true; + second_received_packet->ssrc = header.ssrc; + second_received_packet->seq_num = header.sequenceNumber; + ++packet_counter_.num_fec_packets; + + // Copy FEC payload data. + memcpy(second_received_packet->pkt->data, + incoming_rtp_packet + header.headerLength + red_header_length + + block_length, + payload_data_length - red_header_length - block_length); + + second_received_packet->pkt->length = + payload_data_length - red_header_length - block_length; + + } else if (received_packet->is_fec) { + ++packet_counter_.num_fec_packets; + // everything behind the RED header + memcpy(received_packet->pkt->data, + incoming_rtp_packet + header.headerLength + red_header_length, + payload_data_length - red_header_length); + received_packet->pkt->length = payload_data_length - red_header_length; + received_packet->ssrc = + ByteReader<uint32_t>::ReadBigEndian(&incoming_rtp_packet[8]); + + } else { + // Copy RTP header. + memcpy(received_packet->pkt->data, incoming_rtp_packet, + header.headerLength); + + // Set payload type. + received_packet->pkt->data[1] &= 0x80; // Reset RED payload type. + received_packet->pkt->data[1] += payload_type; // Set media payload type. + + // Copy payload data. + memcpy(received_packet->pkt->data + header.headerLength, + incoming_rtp_packet + header.headerLength + red_header_length, + payload_data_length - red_header_length); + received_packet->pkt->length = + header.headerLength + payload_data_length - red_header_length; + } + + if (received_packet->pkt->length == 0) { + return 0; + } + + received_packets_.push_back(std::move(received_packet)); + if (second_received_packet) { + received_packets_.push_back(std::move(second_received_packet)); + } + return 0; +} + +// TODO(nisse): Drop always-zero return value. +int32_t UlpfecReceiverImpl::ProcessReceivedFec() { + crit_sect_.Enter(); + for (const auto& received_packet : received_packets_) { + // Send received media packet to VCM. + if (!received_packet->is_fec) { + ForwardErrorCorrection::Packet* packet = received_packet->pkt; + crit_sect_.Leave(); + recovered_packet_callback_->OnRecoveredPacket(packet->data, + packet->length); + crit_sect_.Enter(); + } + fec_->DecodeFec(*received_packet, &recovered_packets_); + } + received_packets_.clear(); + + // Send any recovered media packets to VCM. + for (const auto& recovered_packet : recovered_packets_) { + if (recovered_packet->returned) { + // Already sent to the VCM and the jitter buffer. + continue; + } + ForwardErrorCorrection::Packet* packet = recovered_packet->pkt; + ++packet_counter_.num_recovered_packets; + // Set this flag first; in case the recovered packet carries a RED + // header, OnRecoveredPacket will recurse back here. + recovered_packet->returned = true; + crit_sect_.Leave(); + recovered_packet_callback_->OnRecoveredPacket(packet->data, + packet->length); + crit_sect_.Enter(); + } + crit_sect_.Leave(); + return 0; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.h new file mode 100644 index 0000000000..edc3d31269 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.h @@ -0,0 +1,57 @@ +/* + * 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 MODULES_RTP_RTCP_SOURCE_ULPFEC_RECEIVER_IMPL_H_ +#define MODULES_RTP_RTCP_SOURCE_ULPFEC_RECEIVER_IMPL_H_ + +#include <memory> +#include <vector> + +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/include/ulpfec_receiver.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "rtc_base/criticalsection.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +class UlpfecReceiverImpl : public UlpfecReceiver { + public: + explicit UlpfecReceiverImpl(uint32_t ssrc, RecoveredPacketReceiver* callback); + virtual ~UlpfecReceiverImpl(); + + int32_t AddReceivedRedPacket(const RTPHeader& rtp_header, + const uint8_t* incoming_rtp_packet, + size_t packet_length, + uint8_t ulpfec_payload_type) override; + + int32_t ProcessReceivedFec() override; + + FecPacketCounter GetPacketCounter() const override; + + private: + const uint32_t ssrc_; + + rtc::CriticalSection crit_sect_; + RecoveredPacketReceiver* recovered_packet_callback_; + std::unique_ptr<ForwardErrorCorrection> fec_; + // TODO(nisse): The AddReceivedRedPacket method adds one or two packets to + // this list at a time, after which it is emptied by ProcessReceivedFec. It + // will make things simpler to merge AddReceivedRedPacket and + // ProcessReceivedFec into a single method, and we can then delete this list. + std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>> + received_packets_; + ForwardErrorCorrection::RecoveredPacketList recovered_packets_; + FecPacketCounter packet_counter_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_ULPFEC_RECEIVER_IMPL_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_unittest.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_unittest.cc new file mode 100644 index 0000000000..c3bd5a7304 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_unittest.cc @@ -0,0 +1,485 @@ +/* + * 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 <string.h> + +#include <list> +#include <memory> + +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "modules/rtp_rtcp/include/ulpfec_receiver.h" +#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" +#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/fec_test_helper.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { +using ::testing::_; +using ::testing::Args; +using ::testing::ElementsAreArray; +using ::testing::Return; + +using test::fec::AugmentedPacket; +using Packet = ForwardErrorCorrection::Packet; +using test::fec::UlpfecPacketGenerator; + +constexpr int kFecPayloadType = 96; +constexpr uint32_t kMediaSsrc = 835424; + +class NullRecoveredPacketReceiver : public RecoveredPacketReceiver { + public: + void OnRecoveredPacket(const uint8_t* packet, size_t length) override {} +}; + +} // namespace + +class UlpfecReceiverTest : public ::testing::Test { + protected: + UlpfecReceiverTest() + : fec_(ForwardErrorCorrection::CreateUlpfec(kMediaSsrc)), + receiver_fec_( + UlpfecReceiver::Create(kMediaSsrc, &recovered_packet_receiver_)), + packet_generator_(kMediaSsrc) {} + + // Generates |num_fec_packets| FEC packets, given |media_packets|. + void EncodeFec(const ForwardErrorCorrection::PacketList& media_packets, + size_t num_fec_packets, + std::list<ForwardErrorCorrection::Packet*>* fec_packets); + + // Generates |num_media_packets| corresponding to a single frame. + void PacketizeFrame(size_t num_media_packets, + size_t frame_offset, + std::list<AugmentedPacket*>* augmented_packets, + ForwardErrorCorrection::PacketList* packets); + + // Build a media packet using |packet_generator_| and add it + // to the receiver. + void BuildAndAddRedMediaPacket(AugmentedPacket* packet); + + // Build a FEC packet using |packet_generator_| and add it + // to the receiver. + void BuildAndAddRedFecPacket(Packet* packet); + + // Ensure that |recovered_packet_receiver_| will be called correctly + // and that the recovered packet will be identical to the lost packet. + void VerifyReconstructedMediaPacket(const AugmentedPacket& packet, + size_t times); + + void InjectGarbagePacketLength(size_t fec_garbage_offset); + + static void SurvivesMaliciousPacket(const uint8_t* data, + size_t length, + uint8_t ulpfec_payload_type); + + MockRecoveredPacketReceiver recovered_packet_receiver_; + std::unique_ptr<ForwardErrorCorrection> fec_; + std::unique_ptr<UlpfecReceiver> receiver_fec_; + UlpfecPacketGenerator packet_generator_; +}; + +void UlpfecReceiverTest::EncodeFec( + const ForwardErrorCorrection::PacketList& media_packets, + size_t num_fec_packets, + std::list<ForwardErrorCorrection::Packet*>* fec_packets) { + const uint8_t protection_factor = + num_fec_packets * 255 / media_packets.size(); + // Unequal protection is turned off, and the number of important + // packets is thus irrelevant. + constexpr int kNumImportantPackets = 0; + constexpr bool kUseUnequalProtection = false; + constexpr FecMaskType kFecMaskType = kFecMaskBursty; + EXPECT_EQ( + 0, fec_->EncodeFec(media_packets, protection_factor, kNumImportantPackets, + kUseUnequalProtection, kFecMaskType, fec_packets)); + ASSERT_EQ(num_fec_packets, fec_packets->size()); +} + +void UlpfecReceiverTest::PacketizeFrame( + size_t num_media_packets, + size_t frame_offset, + std::list<AugmentedPacket*>* augmented_packets, + ForwardErrorCorrection::PacketList* packets) { + packet_generator_.NewFrame(num_media_packets); + for (size_t i = 0; i < num_media_packets; ++i) { + std::unique_ptr<AugmentedPacket> next_packet( + packet_generator_.NextPacket(frame_offset + i, kRtpHeaderSize + 10)); + augmented_packets->push_back(next_packet.get()); + packets->push_back(std::move(next_packet)); + } +} + +void UlpfecReceiverTest::BuildAndAddRedMediaPacket(AugmentedPacket* packet) { + std::unique_ptr<AugmentedPacket> red_packet( + packet_generator_.BuildMediaRedPacket(*packet)); + EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket( + red_packet->header.header, red_packet->data, + red_packet->length, kFecPayloadType)); +} + +void UlpfecReceiverTest::BuildAndAddRedFecPacket(Packet* packet) { + std::unique_ptr<AugmentedPacket> red_packet( + packet_generator_.BuildUlpfecRedPacket(*packet)); + EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket( + red_packet->header.header, red_packet->data, + red_packet->length, kFecPayloadType)); +} + +void UlpfecReceiverTest::VerifyReconstructedMediaPacket( + const AugmentedPacket& packet, + size_t times) { + // Verify that the content of the reconstructed packet is equal to the + // content of |packet|, and that the same content is received |times| number + // of times in a row. + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, packet.length)) + .With(Args<0, 1>(ElementsAreArray(packet.data, packet.length))) + .Times(times); +} + +void UlpfecReceiverTest::InjectGarbagePacketLength(size_t fec_garbage_offset) { + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)); + + const size_t kNumFecPackets = 1; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + PacketizeFrame(2, 0, &augmented_media_packets, &media_packets); + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets, kNumFecPackets, &fec_packets); + ByteWriter<uint16_t>::WriteBigEndian( + &fec_packets.front()->data[fec_garbage_offset], 0x4711); + + // Inject first media packet, then first FEC packet, skipping the second media + // packet to cause a recovery from the FEC packet. + BuildAndAddRedMediaPacket(augmented_media_packets.front()); + BuildAndAddRedFecPacket(fec_packets.front()); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + + FecPacketCounter counter = receiver_fec_->GetPacketCounter(); + EXPECT_EQ(2U, counter.num_packets); + EXPECT_EQ(1U, counter.num_fec_packets); + EXPECT_EQ(0U, counter.num_recovered_packets); +} + +void UlpfecReceiverTest::SurvivesMaliciousPacket(const uint8_t* data, + size_t length, + uint8_t ulpfec_payload_type) { + RTPHeader header; + std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create()); + ASSERT_TRUE(parser->Parse(data, length, &header)); + + NullRecoveredPacketReceiver null_callback; + std::unique_ptr<UlpfecReceiver> receiver_fec( + UlpfecReceiver::Create(kMediaSsrc, &null_callback)); + + receiver_fec->AddReceivedRedPacket(header, data, length, ulpfec_payload_type); +} + +TEST_F(UlpfecReceiverTest, TwoMediaOneFec) { + constexpr size_t kNumFecPackets = 1u; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + PacketizeFrame(2, 0, &augmented_media_packets, &media_packets); + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets, kNumFecPackets, &fec_packets); + + FecPacketCounter counter = receiver_fec_->GetPacketCounter(); + EXPECT_EQ(0u, counter.num_packets); + EXPECT_EQ(-1, counter.first_packet_time_ms); + + // Recovery + auto it = augmented_media_packets.begin(); + BuildAndAddRedMediaPacket(*it); + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + counter = receiver_fec_->GetPacketCounter(); + EXPECT_EQ(1u, counter.num_packets); + EXPECT_EQ(0u, counter.num_fec_packets); + EXPECT_EQ(0u, counter.num_recovered_packets); + const int64_t first_packet_time_ms = counter.first_packet_time_ms; + EXPECT_NE(-1, first_packet_time_ms); + + // Drop one media packet. + auto fec_it = fec_packets.begin(); + BuildAndAddRedFecPacket(*fec_it); + ++it; + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + + counter = receiver_fec_->GetPacketCounter(); + EXPECT_EQ(2u, counter.num_packets); + EXPECT_EQ(1u, counter.num_fec_packets); + EXPECT_EQ(1u, counter.num_recovered_packets); + EXPECT_EQ(first_packet_time_ms, counter.first_packet_time_ms); +} + +TEST_F(UlpfecReceiverTest, InjectGarbageFecHeaderLengthRecovery) { + // Byte offset 8 is the 'length recovery' field of the FEC header. + InjectGarbagePacketLength(8); +} + +TEST_F(UlpfecReceiverTest, InjectGarbageFecLevelHeaderProtectionLength) { + // Byte offset 10 is the 'protection length' field in the first FEC level + // header. + InjectGarbagePacketLength(10); +} + +TEST_F(UlpfecReceiverTest, TwoMediaTwoFec) { + const size_t kNumFecPackets = 2; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + PacketizeFrame(2, 0, &augmented_media_packets, &media_packets); + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets, kNumFecPackets, &fec_packets); + + // Recovery + // Drop both media packets. + auto it = augmented_media_packets.begin(); + auto fec_it = fec_packets.begin(); + BuildAndAddRedFecPacket(*fec_it); + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + ++fec_it; + BuildAndAddRedFecPacket(*fec_it); + ++it; + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); +} + +TEST_F(UlpfecReceiverTest, TwoFramesOneFec) { + const size_t kNumFecPackets = 1; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + PacketizeFrame(1, 0, &augmented_media_packets, &media_packets); + PacketizeFrame(1, 1, &augmented_media_packets, &media_packets); + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets, kNumFecPackets, &fec_packets); + + // Recovery + auto it = augmented_media_packets.begin(); + BuildAndAddRedMediaPacket(augmented_media_packets.front()); + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + // Drop one media packet. + BuildAndAddRedFecPacket(fec_packets.front()); + ++it; + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); +} + +TEST_F(UlpfecReceiverTest, OneCompleteOneUnrecoverableFrame) { + const size_t kNumFecPackets = 1; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + PacketizeFrame(1, 0, &augmented_media_packets, &media_packets); + PacketizeFrame(2, 1, &augmented_media_packets, &media_packets); + + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets, kNumFecPackets, &fec_packets); + + // Recovery + auto it = augmented_media_packets.begin(); + BuildAndAddRedMediaPacket(*it); // First frame: one packet. + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + ++it; + BuildAndAddRedMediaPacket(*it); // First packet of second frame. + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); +} + +TEST_F(UlpfecReceiverTest, MaxFramesOneFec) { + const size_t kNumFecPackets = 1; + const size_t kNumMediaPackets = 48; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + for (size_t i = 0; i < kNumMediaPackets; ++i) { + PacketizeFrame(1, i, &augmented_media_packets, &media_packets); + } + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets, kNumFecPackets, &fec_packets); + + // Recovery + auto it = augmented_media_packets.begin(); + ++it; // Drop first packet. + for (; it != augmented_media_packets.end(); ++it) { + BuildAndAddRedMediaPacket(*it); + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + } + BuildAndAddRedFecPacket(fec_packets.front()); + it = augmented_media_packets.begin(); + VerifyReconstructedMediaPacket(**it, 1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); +} + +TEST_F(UlpfecReceiverTest, TooManyFrames) { + const size_t kNumFecPackets = 1; + const size_t kNumMediaPackets = 49; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + for (size_t i = 0; i < kNumMediaPackets; ++i) { + PacketizeFrame(1, i, &augmented_media_packets, &media_packets); + } + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EXPECT_EQ(-1, fec_->EncodeFec(media_packets, + kNumFecPackets * 255 / kNumMediaPackets, 0, + false, kFecMaskBursty, &fec_packets)); +} + +TEST_F(UlpfecReceiverTest, PacketNotDroppedTooEarly) { + // 1 frame with 2 media packets and one FEC packet. One media packet missing. + // Delay the FEC packet. + Packet* delayed_fec = nullptr; + const size_t kNumFecPacketsBatch1 = 1; + const size_t kNumMediaPacketsBatch1 = 2; + std::list<AugmentedPacket*> augmented_media_packets_batch1; + ForwardErrorCorrection::PacketList media_packets_batch1; + PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1, + &media_packets_batch1); + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets); + + BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front()); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)) + .Times(1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + delayed_fec = fec_packets.front(); + + // Fill the FEC decoder. No packets should be dropped. + const size_t kNumMediaPacketsBatch2 = 46; + std::list<AugmentedPacket*> augmented_media_packets_batch2; + ForwardErrorCorrection::PacketList media_packets_batch2; + for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) { + PacketizeFrame(1, i, &augmented_media_packets_batch2, + &media_packets_batch2); + } + for (auto it = augmented_media_packets_batch2.begin(); + it != augmented_media_packets_batch2.end(); ++it) { + BuildAndAddRedMediaPacket(*it); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)) + .Times(1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + } + + // Add the delayed FEC packet. One packet should be reconstructed. + BuildAndAddRedFecPacket(delayed_fec); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)) + .Times(1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); +} + +TEST_F(UlpfecReceiverTest, PacketDroppedWhenTooOld) { + // 1 frame with 2 media packets and one FEC packet. One media packet missing. + // Delay the FEC packet. + Packet* delayed_fec = nullptr; + const size_t kNumFecPacketsBatch1 = 1; + const size_t kNumMediaPacketsBatch1 = 2; + std::list<AugmentedPacket*> augmented_media_packets_batch1; + ForwardErrorCorrection::PacketList media_packets_batch1; + PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1, + &media_packets_batch1); + std::list<ForwardErrorCorrection::Packet*> fec_packets; + EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets); + + BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front()); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)) + .Times(1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + delayed_fec = fec_packets.front(); + + // Fill the FEC decoder and force the last packet to be dropped. + const size_t kNumMediaPacketsBatch2 = 48; + std::list<AugmentedPacket*> augmented_media_packets_batch2; + ForwardErrorCorrection::PacketList media_packets_batch2; + for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) { + PacketizeFrame(1, i, &augmented_media_packets_batch2, + &media_packets_batch2); + } + for (auto it = augmented_media_packets_batch2.begin(); + it != augmented_media_packets_batch2.end(); ++it) { + BuildAndAddRedMediaPacket(*it); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)) + .Times(1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + } + + // Add the delayed FEC packet. No packet should be reconstructed since the + // first media packet of that frame has been dropped due to being too old. + BuildAndAddRedFecPacket(delayed_fec); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); +} + +TEST_F(UlpfecReceiverTest, OldFecPacketDropped) { + // 49 frames with 2 media packets and one FEC packet. All media packets + // missing. + const size_t kNumMediaPackets = 49 * 2; + std::list<AugmentedPacket*> augmented_media_packets; + ForwardErrorCorrection::PacketList media_packets; + for (size_t i = 0; i < kNumMediaPackets / 2; ++i) { + std::list<AugmentedPacket*> frame_augmented_media_packets; + ForwardErrorCorrection::PacketList frame_media_packets; + std::list<ForwardErrorCorrection::Packet*> fec_packets; + PacketizeFrame(2, 0, &frame_augmented_media_packets, &frame_media_packets); + EncodeFec(frame_media_packets, 1, &fec_packets); + for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) { + // Only FEC packets inserted. No packets recoverable at this time. + BuildAndAddRedFecPacket(*it); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); + } + // Move unique_ptr's to media_packets for lifetime management. + media_packets.insert(media_packets.end(), + std::make_move_iterator(frame_media_packets.begin()), + std::make_move_iterator(frame_media_packets.end())); + augmented_media_packets.insert(augmented_media_packets.end(), + frame_augmented_media_packets.begin(), + frame_augmented_media_packets.end()); + } + // Insert the oldest media packet. The corresponding FEC packet is too old + // and should have been dropped. Only the media packet we inserted will be + // returned. + BuildAndAddRedMediaPacket(augmented_media_packets.front()); + EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)) + .Times(1); + EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec()); +} + +TEST_F(UlpfecReceiverTest, TruncatedPacketWithFBitSet) { + const uint8_t kTruncatedPacket[] = {0x80, 0x2a, 0x68, 0x71, 0x29, 0xa1, 0x27, + 0x3a, 0x29, 0x12, 0x2a, 0x98, 0xe0, 0x29}; + + SurvivesMaliciousPacket(kTruncatedPacket, sizeof(kTruncatedPacket), 100); +} + +TEST_F(UlpfecReceiverTest, + TruncatedPacketWithFBitSetEndingAfterFirstRedHeader) { + const uint8_t kPacket[] = { + 0x89, 0x27, 0x3a, 0x83, 0x27, 0x3a, 0x3a, 0xf3, 0x67, 0xbe, 0x2a, + 0xa9, 0x27, 0x54, 0x3a, 0x3a, 0x2a, 0x67, 0x3a, 0xf3, 0x67, 0xbe, + 0x2a, 0x27, 0xe6, 0xf6, 0x03, 0x3e, 0x29, 0x27, 0x21, 0x27, 0x2a, + 0x29, 0x21, 0x4b, 0x29, 0x3a, 0x28, 0x29, 0xbf, 0x29, 0x2a, 0x26, + 0x29, 0xae, 0x27, 0xa6, 0xf6, 0x00, 0x03, 0x3e}; + SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100); +} + +TEST_F(UlpfecReceiverTest, TruncatedPacketWithoutDataPastFirstBlock) { + const uint8_t kPacket[] = { + 0x82, 0x38, 0x92, 0x38, 0x92, 0x38, 0xde, 0x2a, 0x11, 0xc8, 0xa3, 0xc4, + 0x82, 0x38, 0x2a, 0x21, 0x2a, 0x28, 0x92, 0x38, 0x92, 0x00, 0x00, 0x0a, + 0x3a, 0xc8, 0xa3, 0x3a, 0x27, 0xc4, 0x2a, 0x21, 0x2a, 0x28}; + SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/video_codec_information.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/video_codec_information.h new file mode 100644 index 0000000000..593d87d01c --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/video_codec_information.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 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_RTP_RTCP_SOURCE_VIDEO_CODEC_INFORMATION_H_ +#define MODULES_RTP_RTCP_SOURCE_VIDEO_CODEC_INFORMATION_H_ + +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "modules/rtp_rtcp/source/rtp_utility.h" + +namespace webrtc { +class VideoCodecInformation { + public: + virtual void Reset() = 0; + + virtual RtpVideoCodecTypes Type() = 0; + virtual ~VideoCodecInformation() {} +}; +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_VIDEO_CODEC_INFORMATION_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc new file mode 100644 index 0000000000..e2afa42856 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc @@ -0,0 +1,163 @@ +/* + * 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 "modules/rtp_rtcp/test/testAPI/test_api.h" + +#include <algorithm> +#include <memory> +#include <vector> + +#include "rtc_base/checks.h" +#include "rtc_base/rate_limiter.h" +#include "test/null_transport.h" + +namespace webrtc { + +void LoopBackTransport::SetSendModule(RtpRtcp* rtp_rtcp_module, + RTPPayloadRegistry* payload_registry, + RtpReceiver* receiver, + ReceiveStatistics* receive_statistics) { + rtp_rtcp_module_ = rtp_rtcp_module; + rtp_payload_registry_ = payload_registry; + rtp_receiver_ = receiver; + receive_statistics_ = receive_statistics; +} + +void LoopBackTransport::DropEveryNthPacket(int n) { + packet_loss_ = n; +} + +bool LoopBackTransport::SendRtp(const uint8_t* data, + size_t len, + const PacketOptions& options) { + count_++; + if (packet_loss_ > 0) { + if ((count_ % packet_loss_) == 0) { + return true; + } + } + RTPHeader header; + std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create()); + if (!parser->Parse(data, len, &header)) { + return false; + } + const auto pl = + rtp_payload_registry_->PayloadTypeToPayload(header.payloadType); + if (!pl) { + return false; + } + const uint8_t* payload = data + header.headerLength; + RTC_CHECK_GE(len, header.headerLength); + const size_t payload_length = len - header.headerLength; + receive_statistics_->IncomingPacket(header, len, false); + return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length, + pl->typeSpecific); +} + +bool LoopBackTransport::SendRtcp(const uint8_t* data, size_t len) { + rtp_rtcp_module_->IncomingRtcpPacket((const uint8_t*)data, len); + return true; +} + +int32_t TestRtpReceiver::OnReceivedPayloadData( + const uint8_t* payload_data, + size_t payload_size, + const webrtc::WebRtcRTPHeader* rtp_header) { + EXPECT_LE(payload_size, sizeof(payload_data_)); + memcpy(payload_data_, payload_data, payload_size); + memcpy(&rtp_header_, rtp_header, sizeof(rtp_header_)); + payload_size_ = payload_size; + return 0; +} + +class RtpRtcpAPITest : public ::testing::Test { + protected: + RtpRtcpAPITest() + : fake_clock_(123456), retransmission_rate_limiter_(&fake_clock_, 1000) { + test_csrcs_.push_back(1234); + test_csrcs_.push_back(2345); + test_ssrc_ = 3456; + test_timestamp_ = 4567; + test_sequence_number_ = 2345; + } + ~RtpRtcpAPITest() {} + + const uint32_t initial_ssrc = 8888; + + void SetUp() override { + RtpRtcp::Configuration configuration; + configuration.audio = true; + configuration.clock = &fake_clock_; + configuration.outgoing_transport = &null_transport_; + configuration.retransmission_rate_limiter = &retransmission_rate_limiter_; + module_.reset(RtpRtcp::CreateRtpRtcp(configuration)); + module_->SetSSRC(initial_ssrc); + rtp_payload_registry_.reset(new RTPPayloadRegistry()); + } + + std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry_; + std::unique_ptr<RtpRtcp> module_; + uint32_t test_ssrc_; + uint32_t test_timestamp_; + uint16_t test_sequence_number_; + std::vector<uint32_t> test_csrcs_; + SimulatedClock fake_clock_; + test::NullTransport null_transport_; + RateLimiter retransmission_rate_limiter_; +}; + +TEST_F(RtpRtcpAPITest, Basic) { + module_->SetSequenceNumber(test_sequence_number_); + EXPECT_EQ(test_sequence_number_, module_->SequenceNumber()); + + module_->SetStartTimestamp(test_timestamp_); + EXPECT_EQ(test_timestamp_, module_->StartTimestamp()); + + EXPECT_FALSE(module_->Sending()); + EXPECT_EQ(0, module_->SetSendingStatus(true)); + EXPECT_TRUE(module_->Sending()); +} + +TEST_F(RtpRtcpAPITest, PacketSize) { + module_->SetMaxRtpPacketSize(1234); + EXPECT_EQ(1234u, module_->MaxRtpPacketSize()); +} + +TEST_F(RtpRtcpAPITest, SSRC) { + module_->SetSSRC(test_ssrc_); + EXPECT_EQ(test_ssrc_, module_->SSRC()); +} + +TEST_F(RtpRtcpAPITest, RTCP) { + EXPECT_EQ(RtcpMode::kOff, module_->RTCP()); + module_->SetRTCPStatus(RtcpMode::kCompound); + EXPECT_EQ(RtcpMode::kCompound, module_->RTCP()); + + EXPECT_EQ(0, module_->SetCNAME("john.doe@test.test")); + + EXPECT_FALSE(module_->TMMBR()); + module_->SetTMMBRStatus(true); + EXPECT_TRUE(module_->TMMBR()); + module_->SetTMMBRStatus(false); + EXPECT_FALSE(module_->TMMBR()); +} + +TEST_F(RtpRtcpAPITest, RtxSender) { + module_->SetRtxSendStatus(kRtxRetransmitted); + EXPECT_EQ(kRtxRetransmitted, module_->RtxSendStatus()); + + module_->SetRtxSendStatus(kRtxOff); + EXPECT_EQ(kRtxOff, module_->RtxSendStatus()); + + module_->SetRtxSendStatus(kRtxRetransmitted); + EXPECT_EQ(kRtxRetransmitted, module_->RtxSendStatus()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h new file mode 100644 index 0000000000..240a4279aa --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h @@ -0,0 +1,72 @@ +/* + * 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 MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_ +#define MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_ + +#include "api/call/transport.h" +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "modules/rtp_rtcp/include/rtp_payload_registry.h" +#include "modules/rtp_rtcp/include/rtp_receiver.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "test/gtest.h" + +namespace webrtc { + +// This class sends all its packet straight to the provided RtpRtcp module. +// with optional packet loss. +class LoopBackTransport : public Transport { + public: + LoopBackTransport() + : count_(0), + packet_loss_(0), + rtp_payload_registry_(NULL), + rtp_receiver_(NULL), + rtp_rtcp_module_(NULL) {} + void SetSendModule(RtpRtcp* rtp_rtcp_module, + RTPPayloadRegistry* payload_registry, + RtpReceiver* receiver, + ReceiveStatistics* receive_statistics); + void DropEveryNthPacket(int n); + bool SendRtp(const uint8_t* data, + size_t len, + const PacketOptions& options) override; + bool SendRtcp(const uint8_t* data, size_t len) override; + + private: + int count_; + int packet_loss_; + ReceiveStatistics* receive_statistics_; + RTPPayloadRegistry* rtp_payload_registry_; + RtpReceiver* rtp_receiver_; + RtpRtcp* rtp_rtcp_module_; +}; + +class TestRtpReceiver : public RtpData { + public: + int32_t OnReceivedPayloadData( + const uint8_t* payload_data, + size_t payload_size, + const webrtc::WebRtcRTPHeader* rtp_header) override; + + const uint8_t* payload_data() const { return payload_data_; } + size_t payload_size() const { return payload_size_; } + webrtc::WebRtcRTPHeader rtp_header() const { return rtp_header_; } + + private: + uint8_t payload_data_[1500]; + size_t payload_size_; + webrtc::WebRtcRTPHeader rtp_header_; +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc new file mode 100644 index 0000000000..a668425dcf --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc @@ -0,0 +1,299 @@ +/* + * 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 <algorithm> +#include <memory> +#include <vector> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/audio_coding/codecs/audio_format_conversion.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_receiver_audio.h" +#include "modules/rtp_rtcp/test/testAPI/test_api.h" +#include "rtc_base/rate_limiter.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +const uint32_t kTestRate = 64000u; +const uint8_t kTestPayload[] = { 't', 'e', 's', 't' }; +const uint8_t kPcmuPayloadType = 96; +const uint8_t kDtmfPayloadType = 97; + +struct CngCodecSpec { + int payload_type; + int clockrate_hz; +}; + +const CngCodecSpec kCngCodecs[] = {{13, 8000}, + {103, 16000}, + {104, 32000}, + {105, 48000}}; + +bool IsComfortNoisePayload(uint8_t payload_type) { + for (const auto& c : kCngCodecs) { + if (c.payload_type == payload_type) + return true; + } + + return false; +} + +class VerifyingAudioReceiver : public RtpData { + public: + int32_t OnReceivedPayloadData( + const uint8_t* payloadData, + size_t payloadSize, + const webrtc::WebRtcRTPHeader* rtpHeader) override { + const uint8_t payload_type = rtpHeader->header.payloadType; + if (payload_type == kPcmuPayloadType || payload_type == kDtmfPayloadType) { + EXPECT_EQ(sizeof(kTestPayload), payloadSize); + // All our test vectors for PCMU and DTMF are equal to |kTestPayload|. + const size_t min_size = std::min(sizeof(kTestPayload), payloadSize); + EXPECT_EQ(0, memcmp(payloadData, kTestPayload, min_size)); + } else if (IsComfortNoisePayload(payload_type)) { + // CNG types should be recognized properly. + EXPECT_EQ(kAudioFrameCN, rtpHeader->frameType); + EXPECT_TRUE(rtpHeader->type.Audio.isCNG); + } + return 0; + } +}; + +class RTPCallback : public NullRtpFeedback { + public: + int32_t OnInitializeDecoder(int payload_type, + const SdpAudioFormat& audio_format, + uint32_t rate) override { + EXPECT_EQ(0u, rate) << "The rate should be zero"; + return 0; + } +}; + +} // namespace + +class RtpRtcpAudioTest : public ::testing::Test { + protected: + RtpRtcpAudioTest() + : fake_clock(123456), retransmission_rate_limiter_(&fake_clock, 1000) { + test_CSRC[0] = 1234; + test_CSRC[2] = 2345; + test_ssrc = 3456; + test_timestamp = 4567; + test_sequence_number = 2345; + } + ~RtpRtcpAudioTest() {} + + void SetUp() override { + receive_statistics1_.reset(ReceiveStatistics::Create(&fake_clock)); + receive_statistics2_.reset(ReceiveStatistics::Create(&fake_clock)); + + rtp_payload_registry1_.reset(new RTPPayloadRegistry()); + rtp_payload_registry2_.reset(new RTPPayloadRegistry()); + + RtpRtcp::Configuration configuration; + configuration.audio = true; + configuration.clock = &fake_clock; + configuration.receive_statistics = receive_statistics1_.get(); + configuration.outgoing_transport = &transport1; + configuration.retransmission_rate_limiter = &retransmission_rate_limiter_; + + module1.reset(RtpRtcp::CreateRtpRtcp(configuration)); + rtp_receiver1_.reset(RtpReceiver::CreateAudioReceiver( + &fake_clock, &data_receiver1, &rtp_callback, + rtp_payload_registry1_.get())); + + configuration.receive_statistics = receive_statistics2_.get(); + configuration.outgoing_transport = &transport2; + + module2.reset(RtpRtcp::CreateRtpRtcp(configuration)); + rtp_receiver2_.reset(RtpReceiver::CreateAudioReceiver( + &fake_clock, &data_receiver2, &rtp_callback, + rtp_payload_registry2_.get())); + + transport1.SetSendModule(module2.get(), rtp_payload_registry2_.get(), + rtp_receiver2_.get(), receive_statistics2_.get()); + transport2.SetSendModule(module1.get(), rtp_payload_registry1_.get(), + rtp_receiver1_.get(), receive_statistics1_.get()); + } + + void RegisterPayload(const CodecInst& codec) { + EXPECT_EQ(0, module1->RegisterSendPayload(codec)); + EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload(codec.pltype, + CodecInstToSdp(codec))); + EXPECT_EQ(0, module2->RegisterSendPayload(codec)); + EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(codec.pltype, + CodecInstToSdp(codec))); + } + + VerifyingAudioReceiver data_receiver1; + VerifyingAudioReceiver data_receiver2; + RTPCallback rtp_callback; + std::unique_ptr<ReceiveStatistics> receive_statistics1_; + std::unique_ptr<ReceiveStatistics> receive_statistics2_; + std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry1_; + std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry2_; + std::unique_ptr<RtpReceiver> rtp_receiver1_; + std::unique_ptr<RtpReceiver> rtp_receiver2_; + std::unique_ptr<RtpRtcp> module1; + std::unique_ptr<RtpRtcp> module2; + LoopBackTransport transport1; + LoopBackTransport transport2; + uint32_t test_ssrc; + uint32_t test_timestamp; + uint16_t test_sequence_number; + uint32_t test_CSRC[webrtc::kRtpCsrcSize]; + SimulatedClock fake_clock; + RateLimiter retransmission_rate_limiter_; +}; + +TEST_F(RtpRtcpAudioTest, Basic) { + module1->SetSSRC(test_ssrc); + module1->SetStartTimestamp(test_timestamp); + + // Test detection at the end of a DTMF tone. + // EXPECT_EQ(0, module2->SetTelephoneEventForwardToDecoder(true)); + + EXPECT_EQ(0, module1->SetSendingStatus(true)); + + // Start basic RTP test. + + // Send an empty RTP packet. + // Should fail since we have not registered the payload type. + EXPECT_FALSE(module1->SendOutgoingData(webrtc::kAudioFrameSpeech, + kPcmuPayloadType, 0, -1, nullptr, 0, + nullptr, nullptr, nullptr)); + + CodecInst voice_codec = {}; + voice_codec.pltype = kPcmuPayloadType; + voice_codec.plfreq = 8000; + voice_codec.rate = kTestRate; + memcpy(voice_codec.plname, "PCMU", 5); + RegisterPayload(voice_codec); + + EXPECT_TRUE(module1->SendOutgoingData(webrtc::kAudioFrameSpeech, + kPcmuPayloadType, 0, -1, kTestPayload, + 4, nullptr, nullptr, nullptr)); + + EXPECT_EQ(test_ssrc, rtp_receiver2_->SSRC()); + uint32_t timestamp; + int64_t receive_time_ms; + EXPECT_TRUE( + rtp_receiver2_->GetLatestTimestamps(×tamp, &receive_time_ms)); + EXPECT_EQ(test_timestamp, timestamp); + EXPECT_EQ(fake_clock.TimeInMilliseconds(), receive_time_ms); +} + +TEST_F(RtpRtcpAudioTest, DTMF) { + CodecInst voice_codec = {}; + voice_codec.pltype = kPcmuPayloadType; + voice_codec.plfreq = 8000; + voice_codec.rate = kTestRate; + memcpy(voice_codec.plname, "PCMU", 5); + RegisterPayload(voice_codec); + + module1->SetSSRC(test_ssrc); + module1->SetStartTimestamp(test_timestamp); + EXPECT_EQ(0, module1->SetSendingStatus(true)); + + // Prepare for DTMF. + voice_codec.pltype = kDtmfPayloadType; + voice_codec.plfreq = 8000; + memcpy(voice_codec.plname, "telephone-event", 16); + + EXPECT_EQ(0, module1->RegisterSendPayload(voice_codec)); + EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload( + voice_codec.pltype, CodecInstToSdp(voice_codec))); + + // Start DTMF test. + int timeStamp = 160; + + // Send a DTMF tone using RFC 2833 (4733). + for (int i = 0; i < 16; i++) { + EXPECT_EQ(0, module1->SendTelephoneEventOutband(i, timeStamp, 10)); + } + timeStamp += 160; // Prepare for next packet. + + // Send RTP packets for 16 tones a 160 ms 100ms + // pause between = 2560ms + 1600ms = 4160ms + for (; timeStamp <= 250 * 160; timeStamp += 160) { + EXPECT_TRUE(module1->SendOutgoingData( + webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1, + kTestPayload, 4, nullptr, nullptr, nullptr)); + fake_clock.AdvanceTimeMilliseconds(20); + module1->Process(); + } + EXPECT_EQ(0, module1->SendTelephoneEventOutband(32, 9000, 10)); + + for (; timeStamp <= 740 * 160; timeStamp += 160) { + EXPECT_TRUE(module1->SendOutgoingData( + webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1, + kTestPayload, 4, nullptr, nullptr, nullptr)); + fake_clock.AdvanceTimeMilliseconds(20); + module1->Process(); + } +} + +TEST_F(RtpRtcpAudioTest, ComfortNoise) { + module1->SetSSRC(test_ssrc); + module1->SetStartTimestamp(test_timestamp); + + EXPECT_EQ(0, module1->SetSendingStatus(true)); + + // Register PCMU and all four comfort noise codecs + CodecInst voice_codec = {}; + voice_codec.pltype = kPcmuPayloadType; + voice_codec.plfreq = 8000; + voice_codec.rate = kTestRate; + memcpy(voice_codec.plname, "PCMU", 5); + RegisterPayload(voice_codec); + + for (const auto& c : kCngCodecs) { + CodecInst cng_codec = {}; + cng_codec.pltype = c.payload_type; + cng_codec.plfreq = c.clockrate_hz; + memcpy(cng_codec.plname, "CN", 3); + RegisterPayload(cng_codec); + } + + // Transmit comfort noise packets interleaved by PCMU packets. + uint32_t in_timestamp = 0; + for (const auto& c : kCngCodecs) { + uint32_t timestamp; + int64_t receive_time_ms; + EXPECT_TRUE(module1->SendOutgoingData( + webrtc::kAudioFrameSpeech, kPcmuPayloadType, in_timestamp, -1, + kTestPayload, 4, nullptr, nullptr, nullptr)); + + EXPECT_EQ(test_ssrc, rtp_receiver2_->SSRC()); + EXPECT_TRUE( + rtp_receiver2_->GetLatestTimestamps(×tamp, &receive_time_ms)); + EXPECT_EQ(test_timestamp + in_timestamp, timestamp); + EXPECT_EQ(fake_clock.TimeInMilliseconds(), receive_time_ms); + in_timestamp += 10; + fake_clock.AdvanceTimeMilliseconds(20); + + EXPECT_TRUE(module1->SendOutgoingData(webrtc::kAudioFrameCN, c.payload_type, + in_timestamp, -1, kTestPayload, 1, + nullptr, nullptr, nullptr)); + + EXPECT_EQ(test_ssrc, rtp_receiver2_->SSRC()); + EXPECT_TRUE( + rtp_receiver2_->GetLatestTimestamps(×tamp, &receive_time_ms)); + EXPECT_EQ(test_timestamp + in_timestamp, timestamp); + EXPECT_EQ(fake_clock.TimeInMilliseconds(), receive_time_ms); + in_timestamp += 10; + fake_clock.AdvanceTimeMilliseconds(20); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc new file mode 100644 index 0000000000..4b5b50b8b6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc @@ -0,0 +1,252 @@ +/* + * 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 <algorithm> +#include <memory> +#include <vector> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/audio_coding/codecs/audio_format_conversion.h" +#include "modules/rtp_rtcp/include/receive_statistics.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_receiver_audio.h" +#include "modules/rtp_rtcp/test/testAPI/test_api.h" +#include "rtc_base/rate_limiter.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +class RtcpCallback : public RtcpIntraFrameObserver { + public: + void SetModule(RtpRtcp* module) { + _rtpRtcpModule = module; + } + virtual void OnRTCPPacketTimeout(const int32_t id) { + } + virtual void OnLipSyncUpdate(const int32_t id, + const int32_t audioVideoOffset) {} + virtual void OnReceivedIntraFrameRequest(uint32_t ssrc) {} + + private: + RtpRtcp* _rtpRtcpModule; +}; + +class TestRtpFeedback : public NullRtpFeedback { + public: + explicit TestRtpFeedback(RtpRtcp* rtp_rtcp) : rtp_rtcp_(rtp_rtcp) {} + virtual ~TestRtpFeedback() {} + + void OnIncomingSSRCChanged(uint32_t ssrc) override { + rtp_rtcp_->SetRemoteSSRC(ssrc); + } + + private: + RtpRtcp* rtp_rtcp_; +}; + +class RtpRtcpRtcpTest : public ::testing::Test { + protected: + RtpRtcpRtcpTest() + : fake_clock(123456), retransmission_rate_limiter_(&fake_clock, 1000) { + test_csrcs.push_back(1234); + test_csrcs.push_back(2345); + test_ssrc = 3456; + test_timestamp = 4567; + test_sequence_number = 2345; + } + ~RtpRtcpRtcpTest() {} + + virtual void SetUp() { + receiver = new TestRtpReceiver(); + transport1 = new LoopBackTransport(); + transport2 = new LoopBackTransport(); + myRTCPFeedback1 = new RtcpCallback(); + myRTCPFeedback2 = new RtcpCallback(); + + receive_statistics1_.reset(ReceiveStatistics::Create(&fake_clock)); + receive_statistics2_.reset(ReceiveStatistics::Create(&fake_clock)); + + RtpRtcp::Configuration configuration; + configuration.audio = true; + configuration.clock = &fake_clock; + configuration.receive_statistics = receive_statistics1_.get(); + configuration.outgoing_transport = transport1; + configuration.intra_frame_callback = myRTCPFeedback1; + configuration.retransmission_rate_limiter = &retransmission_rate_limiter_; + + rtp_payload_registry1_.reset(new RTPPayloadRegistry()); + rtp_payload_registry2_.reset(new RTPPayloadRegistry()); + + module1 = RtpRtcp::CreateRtpRtcp(configuration); + + rtp_feedback1_.reset(new TestRtpFeedback(module1)); + + rtp_receiver1_.reset(RtpReceiver::CreateAudioReceiver( + &fake_clock, receiver, rtp_feedback1_.get(), + rtp_payload_registry1_.get())); + + configuration.receive_statistics = receive_statistics2_.get(); + configuration.outgoing_transport = transport2; + configuration.intra_frame_callback = myRTCPFeedback2; + + module2 = RtpRtcp::CreateRtpRtcp(configuration); + + rtp_feedback2_.reset(new TestRtpFeedback(module2)); + + rtp_receiver2_.reset(RtpReceiver::CreateAudioReceiver( + &fake_clock, receiver, rtp_feedback2_.get(), + rtp_payload_registry2_.get())); + + transport1->SetSendModule(module2, rtp_payload_registry2_.get(), + rtp_receiver2_.get(), receive_statistics2_.get()); + transport2->SetSendModule(module1, rtp_payload_registry1_.get(), + rtp_receiver1_.get(), receive_statistics1_.get()); + myRTCPFeedback1->SetModule(module1); + myRTCPFeedback2->SetModule(module2); + + module1->SetRTCPStatus(RtcpMode::kCompound); + module2->SetRTCPStatus(RtcpMode::kCompound); + + module2->SetSSRC(test_ssrc + 1); + module1->SetSSRC(test_ssrc); + module1->SetSequenceNumber(test_sequence_number); + module1->SetStartTimestamp(test_timestamp); + + module1->SetCsrcs(test_csrcs); + EXPECT_EQ(0, module1->SetCNAME("john.doe@test.test")); + + EXPECT_EQ(0, module1->SetSendingStatus(true)); + + CodecInst voice_codec; + voice_codec.pltype = 96; + voice_codec.plfreq = 8000; + voice_codec.rate = 64000; + memcpy(voice_codec.plname, "PCMU", 5); + + EXPECT_EQ(0, module1->RegisterSendPayload(voice_codec)); + EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload( + voice_codec.pltype, CodecInstToSdp(voice_codec))); + EXPECT_EQ(0, module2->RegisterSendPayload(voice_codec)); + EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload( + voice_codec.pltype, CodecInstToSdp(voice_codec))); + + // We need to send one RTP packet to get the RTCP packet to be accepted by + // the receiving module. + // send RTP packet with the data "testtest" + const uint8_t test[9] = "testtest"; + EXPECT_EQ(true, + module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96, 0, -1, + test, 8, nullptr, nullptr, nullptr)); + } + + virtual void TearDown() { + delete module1; + delete module2; + delete myRTCPFeedback1; + delete myRTCPFeedback2; + delete transport1; + delete transport2; + delete receiver; + } + + std::unique_ptr<TestRtpFeedback> rtp_feedback1_; + std::unique_ptr<TestRtpFeedback> rtp_feedback2_; + std::unique_ptr<ReceiveStatistics> receive_statistics1_; + std::unique_ptr<ReceiveStatistics> receive_statistics2_; + std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry1_; + std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry2_; + std::unique_ptr<RtpReceiver> rtp_receiver1_; + std::unique_ptr<RtpReceiver> rtp_receiver2_; + RtpRtcp* module1; + RtpRtcp* module2; + TestRtpReceiver* receiver; + LoopBackTransport* transport1; + LoopBackTransport* transport2; + RtcpCallback* myRTCPFeedback1; + RtcpCallback* myRTCPFeedback2; + + uint32_t test_ssrc; + uint32_t test_timestamp; + uint16_t test_sequence_number; + std::vector<uint32_t> test_csrcs; + SimulatedClock fake_clock; + RateLimiter retransmission_rate_limiter_; +}; + +TEST_F(RtpRtcpRtcpTest, RTCP_CNAME) { + uint32_t testOfCSRC[webrtc::kRtpCsrcSize]; + EXPECT_EQ(2, rtp_receiver2_->CSRCs(testOfCSRC)); + EXPECT_EQ(test_csrcs[0], testOfCSRC[0]); + EXPECT_EQ(test_csrcs[1], testOfCSRC[1]); + + // Set cname of mixed. + EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[0], "john@192.168.0.1")); + EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[1], "jane@192.168.0.2")); + + EXPECT_EQ(-1, module1->RemoveMixedCNAME(test_csrcs[0] + 1)); + EXPECT_EQ(0, module1->RemoveMixedCNAME(test_csrcs[1])); + EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[1], "jane@192.168.0.2")); + + // send RTCP packet, triggered by timer + fake_clock.AdvanceTimeMilliseconds(7500); + module1->Process(); + fake_clock.AdvanceTimeMilliseconds(100); + module2->Process(); + + char cName[RTCP_CNAME_SIZE]; + EXPECT_EQ(-1, module2->RemoteCNAME(rtp_receiver2_->SSRC() + 1, cName)); + + // Check multiple CNAME. + EXPECT_EQ(0, module2->RemoteCNAME(rtp_receiver2_->SSRC(), cName)); + EXPECT_EQ(0, strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE)); + + EXPECT_EQ(0, module2->RemoteCNAME(test_csrcs[0], cName)); + EXPECT_EQ(0, strncmp(cName, "john@192.168.0.1", RTCP_CNAME_SIZE)); + + EXPECT_EQ(0, module2->RemoteCNAME(test_csrcs[1], cName)); + EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE)); + + EXPECT_EQ(0, module1->SetSendingStatus(false)); + + // Test that BYE clears the CNAME + EXPECT_EQ(-1, module2->RemoteCNAME(rtp_receiver2_->SSRC(), cName)); +} + +TEST_F(RtpRtcpRtcpTest, RemoteRTCPStatRemote) { + std::vector<RTCPReportBlock> report_blocks; + + EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks)); + EXPECT_EQ(0u, report_blocks.size()); + + // send RTCP packet, triggered by timer + fake_clock.AdvanceTimeMilliseconds(7500); + module1->Process(); + fake_clock.AdvanceTimeMilliseconds(100); + module2->Process(); + + EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks)); + ASSERT_EQ(1u, report_blocks.size()); + + // |test_ssrc+1| is the SSRC of module2 that send the report. + EXPECT_EQ(test_ssrc + 1, report_blocks[0].sender_ssrc); + EXPECT_EQ(test_ssrc, report_blocks[0].source_ssrc); + + EXPECT_EQ(0u, report_blocks[0].packets_lost); + EXPECT_LT(0u, report_blocks[0].delay_since_last_sender_report); + EXPECT_EQ(test_sequence_number, + report_blocks[0].extended_highest_sequence_number); + EXPECT_EQ(0u, report_blocks[0].fraction_lost); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc new file mode 100644 index 0000000000..63b78514dc --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc @@ -0,0 +1,183 @@ +/* + * 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 <stdlib.h> + +#include <algorithm> +#include <memory> +#include <vector> + +#include "common_types.h" // NOLINT(build/include) +#include "modules/rtp_rtcp/include/rtp_payload_registry.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtp_receiver_video.h" +#include "modules/rtp_rtcp/test/testAPI/test_api.h" +#include "rtc_base/rate_limiter.h" +#include "test/gtest.h" + +namespace { + +const unsigned char kPayloadType = 100; + +}; + +namespace webrtc { + +class RtpRtcpVideoTest : public ::testing::Test { + protected: + RtpRtcpVideoTest() + : test_ssrc_(3456), + test_timestamp_(4567), + test_sequence_number_(2345), + fake_clock(123456), + retransmission_rate_limiter_(&fake_clock, 1000) {} + ~RtpRtcpVideoTest() {} + + virtual void SetUp() { + transport_ = new LoopBackTransport(); + receiver_ = new TestRtpReceiver(); + receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock)); + RtpRtcp::Configuration configuration; + configuration.audio = false; + configuration.clock = &fake_clock; + configuration.outgoing_transport = transport_; + configuration.retransmission_rate_limiter = &retransmission_rate_limiter_; + + video_module_ = RtpRtcp::CreateRtpRtcp(configuration); + rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver( + &fake_clock, receiver_, NULL, &rtp_payload_registry_)); + + video_module_->SetRTCPStatus(RtcpMode::kCompound); + video_module_->SetSSRC(test_ssrc_); + video_module_->SetStorePacketsStatus(true, 600); + EXPECT_EQ(0, video_module_->SetSendingStatus(true)); + + transport_->SetSendModule(video_module_, &rtp_payload_registry_, + rtp_receiver_.get(), receive_statistics_.get()); + + VideoCodec video_codec; + memset(&video_codec, 0, sizeof(video_codec)); + video_codec.plType = 123; + memcpy(video_codec.plName, "I420", 5); + + EXPECT_EQ(0, video_module_->RegisterSendPayload(video_codec)); + EXPECT_EQ(0, rtp_payload_registry_.RegisterReceivePayload(video_codec)); + + payload_data_length_ = sizeof(video_frame_); + + for (size_t n = 0; n < payload_data_length_; n++) { + video_frame_[n] = n%10; + } + } + + size_t BuildRTPheader(uint8_t* dataBuffer, + uint32_t timestamp, + uint32_t sequence_number) { + dataBuffer[0] = static_cast<uint8_t>(0x80); // version 2 + dataBuffer[1] = static_cast<uint8_t>(kPayloadType); + ByteWriter<uint16_t>::WriteBigEndian(dataBuffer + 2, sequence_number); + ByteWriter<uint32_t>::WriteBigEndian(dataBuffer + 4, timestamp); + ByteWriter<uint32_t>::WriteBigEndian(dataBuffer + 8, 0x1234); // SSRC. + size_t rtpHeaderLength = 12; + return rtpHeaderLength; + } + + size_t PaddingPacket(uint8_t* buffer, + uint32_t timestamp, + uint32_t sequence_number, + size_t bytes) { + // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP. + size_t max_length = 224; + + size_t padding_bytes_in_packet = max_length; + if (bytes < max_length) { + padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32. + } + // Correct seq num, timestamp and payload type. + size_t header_length = BuildRTPheader(buffer, timestamp, sequence_number); + buffer[0] |= 0x20; // Set padding bit. + int32_t* data = + reinterpret_cast<int32_t*>(&(buffer[header_length])); + + // Fill data buffer with random data. + for (size_t j = 0; j < (padding_bytes_in_packet >> 2); j++) { + data[j] = rand(); // NOLINT + } + // Set number of padding bytes in the last byte of the packet. + buffer[header_length + padding_bytes_in_packet - 1] = + padding_bytes_in_packet; + return padding_bytes_in_packet + header_length; + } + + virtual void TearDown() { + delete video_module_; + delete transport_; + delete receiver_; + } + + int test_id_; + std::unique_ptr<ReceiveStatistics> receive_statistics_; + RTPPayloadRegistry rtp_payload_registry_; + std::unique_ptr<RtpReceiver> rtp_receiver_; + RtpRtcp* video_module_; + LoopBackTransport* transport_; + TestRtpReceiver* receiver_; + uint32_t test_ssrc_; + uint32_t test_timestamp_; + uint16_t test_sequence_number_; + uint8_t video_frame_[65000]; + size_t payload_data_length_; + SimulatedClock fake_clock; + RateLimiter retransmission_rate_limiter_; +}; + +TEST_F(RtpRtcpVideoTest, BasicVideo) { + uint32_t timestamp = 3000; + EXPECT_TRUE(video_module_->SendOutgoingData( + kVideoFrameDelta, 123, timestamp, timestamp / 90, video_frame_, + payload_data_length_, nullptr, nullptr, nullptr)); +} + +TEST_F(RtpRtcpVideoTest, PaddingOnlyFrames) { + const size_t kPadSize = 255; + uint8_t padding_packet[kPadSize]; + uint32_t seq_num = 0; + uint32_t timestamp = 3000; + VideoCodec codec; + codec.codecType = kVideoCodecVP8; + codec.plType = kPayloadType; + strncpy(codec.plName, "VP8", 4); + EXPECT_EQ(0, rtp_payload_registry_.RegisterReceivePayload(codec)); + for (int frame_idx = 0; frame_idx < 10; ++frame_idx) { + for (int packet_idx = 0; packet_idx < 5; ++packet_idx) { + size_t packet_size = PaddingPacket(padding_packet, timestamp, seq_num, + kPadSize); + ++seq_num; + RTPHeader header; + std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create()); + EXPECT_TRUE(parser->Parse(padding_packet, packet_size, &header)); + const auto pl = + rtp_payload_registry_.PayloadTypeToPayload(header.payloadType); + EXPECT_TRUE(pl); + const uint8_t* payload = padding_packet + header.headerLength; + const size_t payload_length = packet_size - header.headerLength; + EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket( + header, payload, payload_length, pl->typeSpecific)); + EXPECT_EQ(0u, receiver_->payload_size()); + EXPECT_EQ(payload_length, receiver_->rtp_header().header.paddingLength); + } + timestamp += 3000; + fake_clock.AdvanceTimeMilliseconds(33); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/average_residual_loss_xor_codes.h b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/average_residual_loss_xor_codes.h new file mode 100644 index 0000000000..ccf9752ee9 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/average_residual_loss_xor_codes.h @@ -0,0 +1,191 @@ +/* + * 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 MODULES_RTP_RTCP_TEST_TESTFEC_AVERAGE_RESIDUAL_LOSS_XOR_CODES_H_ +#define MODULES_RTP_RTCP_TEST_TESTFEC_AVERAGE_RESIDUAL_LOSS_XOR_CODES_H_ + +namespace webrtc { + +// Maximum number of media packets allowed in this test. The burst mask types +// are currently defined up to (kMaxMediaPacketsTest, kMaxMediaPacketsTest). +const int kMaxMediaPacketsTest = 12; + +// Maximum number of FEC codes considered in this test. +const int kNumberCodes = kMaxMediaPacketsTest * (kMaxMediaPacketsTest + 1) / 2; + +// For the random mask type: reference level for the maximum average residual +// loss expected for each code size up to: +// (kMaxMediaPacketsTest, kMaxMediaPacketsTest). +const float kMaxResidualLossRandomMask[kNumberCodes] = { + 0.009463f, + 0.022436f, + 0.007376f, + 0.033895f, + 0.012423f, + 0.004644f, + 0.043438f, + 0.019937f, + 0.008820f, + 0.003438f, + 0.051282f, + 0.025795f, + 0.012872f, + 0.006458f, + 0.003195f, + 0.057728f, + 0.032146f, + 0.016708f, + 0.009242f, + 0.005054f, + 0.003078f, + 0.063050f, + 0.037261f, + 0.021767f, + 0.012447f, + 0.007099f, + 0.003826f, + 0.002504f, + 0.067476f, + 0.042348f, + 0.026169f, + 0.015695f, + 0.009478f, + 0.005887f, + 0.003568f, + 0.001689f, + 0.071187f, + 0.046575f, + 0.031697f, + 0.019797f, + 0.012433f, + 0.007027f, + 0.004845f, + 0.002777f, + 0.001753f, + 0.074326f, + 0.050628f, + 0.034978f, + 0.021955f, + 0.014821f, + 0.009462f, + 0.006393f, + 0.004181f, + 0.003105f, + 0.001231f, + 0.077008f, + 0.054226f, + 0.038407f, + 0.026251f, + 0.018634f, + 0.011568f, + 0.008130f, + 0.004957f, + 0.003334f, + 0.002069f, + 0.001304f, + 0.079318f, + 0.057180f, + 0.041268f, + 0.028842f, + 0.020033f, + 0.014061f, + 0.009636f, + 0.006411f, + 0.004583f, + 0.002817f, + 0.001770f, + 0.001258f +}; + +// For the bursty mask type: reference level for the maximum average residual +// loss expected for each code size up to: +// (kMaxMediaPacketsTestf, kMaxMediaPacketsTest). +const float kMaxResidualLossBurstyMask[kNumberCodes] = { + 0.033236f, + 0.053344f, + 0.026616f, + 0.064129f, + 0.036589f, + 0.021892f, + 0.071055f, + 0.043890f, + 0.028009f, + 0.018524f, + 0.075968f, + 0.049828f, + 0.033288f, + 0.022791f, + 0.016088f, + 0.079672f, + 0.054586f, + 0.037872f, + 0.026679f, + 0.019326f, + 0.014293f, + 0.082582f, + 0.058719f, + 0.042045f, + 0.030504f, + 0.022391f, + 0.016894f, + 0.012946f, + 0.084935f, + 0.062169f, + 0.045620f, + 0.033713f, + 0.025570f, + 0.019439f, + 0.015121f, + 0.011920f, + 0.086881f, + 0.065267f, + 0.048721f, + 0.037613f, + 0.028278f, + 0.022152f, + 0.017314f, + 0.013791f, + 0.011130f, + 0.088516f, + 0.067911f, + 0.051709f, + 0.040819f, + 0.030777f, + 0.024547f, + 0.019689f, + 0.015877f, + 0.012773f, + 0.010516f, + 0.089909f, + 0.070332f, + 0.054402f, + 0.043210f, + 0.034096f, + 0.026625f, + 0.021823f, + 0.017648f, + 0.014649f, + 0.011982f, + 0.010035f, + 0.091109f, + 0.072428f, + 0.056775f, + 0.045418f, + 0.036679f, + 0.028599f, + 0.023693f, + 0.019966f, + 0.016603f, + 0.013690f, + 0.011359f, + 0.009657f +}; + +} // namespace webrtc +#endif // MODULES_RTP_RTCP_TEST_TESTFEC_AVERAGE_RESIDUAL_LOSS_XOR_CODES_H_ diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_fec.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_fec.cc new file mode 100644 index 0000000000..32dc374e4f --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_fec.cc @@ -0,0 +1,478 @@ +/* + * 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. + */ + +/* + * Test application for core FEC algorithm. Calls encoding and decoding + * functions in ForwardErrorCorrection directly. + */ + +#include <string.h> +#include <time.h> + +#include <list> + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/forward_error_correction.h" +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "rtc_base/random.h" +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" + +// #define VERBOSE_OUTPUT + +namespace webrtc { +namespace fec_private_tables { +extern const uint8_t** kPacketMaskBurstyTbl[12]; +} +namespace test { +using fec_private_tables::kPacketMaskBurstyTbl; + +void ReceivePackets( + std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>* + to_decode_list, + std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>* + received_packet_list, + size_t num_packets_to_decode, + float reorder_rate, + float duplicate_rate, + Random* random) { + RTC_DCHECK(to_decode_list->empty()); + RTC_DCHECK_LE(num_packets_to_decode, received_packet_list->size()); + + for (size_t i = 0; i < num_packets_to_decode; i++) { + auto it = received_packet_list->begin(); + // Reorder packets. + float random_variable = random->Rand<float>(); + while (random_variable < reorder_rate) { + ++it; + if (it == received_packet_list->end()) { + --it; + break; + } + random_variable = random->Rand<float>(); + } + to_decode_list->push_back(std::move(*it)); + received_packet_list->erase(it); + + // Duplicate packets. + ForwardErrorCorrection::ReceivedPacket* received_packet = + to_decode_list->back().get(); + random_variable = random->Rand<float>(); + while (random_variable < duplicate_rate) { + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> duplicate_packet( + new ForwardErrorCorrection::ReceivedPacket()); + *duplicate_packet = *received_packet; + duplicate_packet->pkt = new ForwardErrorCorrection::Packet(); + memcpy(duplicate_packet->pkt->data, received_packet->pkt->data, + received_packet->pkt->length); + duplicate_packet->pkt->length = received_packet->pkt->length; + + to_decode_list->push_back(std::move(duplicate_packet)); + random_variable = random->Rand<float>(); + } + } +} + +void RunTest(bool use_flexfec) { + // TODO(marpan): Split this function into subroutines/helper functions. + enum { kMaxNumberMediaPackets = 48 }; + enum { kMaxNumberFecPackets = 48 }; + + const uint32_t kNumMaskBytesL0 = 2; + const uint32_t kNumMaskBytesL1 = 6; + + // FOR UEP + const bool kUseUnequalProtection = true; + + // FEC mask types. + const FecMaskType kMaskTypes[] = {kFecMaskRandom, kFecMaskBursty}; + const int kNumFecMaskTypes = sizeof(kMaskTypes) / sizeof(*kMaskTypes); + + // Maximum number of media packets allowed for the mask type. + const uint16_t kMaxMediaPackets[] = { + kMaxNumberMediaPackets, + sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)}; + + ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not " + << "equal to 12."; + + ForwardErrorCorrection::PacketList media_packet_list; + std::list<ForwardErrorCorrection::Packet*> fec_packet_list; + std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>> + to_decode_list; + std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>> + received_packet_list; + ForwardErrorCorrection::RecoveredPacketList recovered_packet_list; + std::list<uint8_t*> fec_mask_list; + + // Running over only two loss rates to limit execution time. + const float loss_rate[] = {0.05f, 0.01f}; + const uint32_t loss_rate_size = sizeof(loss_rate) / sizeof(*loss_rate); + const float reorder_rate = 0.1f; + const float duplicate_rate = 0.1f; + + uint8_t media_loss_mask[kMaxNumberMediaPackets]; + uint8_t fec_loss_mask[kMaxNumberFecPackets]; + uint8_t fec_packet_masks[kMaxNumberFecPackets][kMaxNumberMediaPackets]; + + // Seed the random number generator, storing the seed to file in order to + // reproduce past results. + const unsigned int random_seed = static_cast<unsigned int>(time(nullptr)); + Random random(random_seed); + std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt"; + FILE* random_seed_file = fopen(filename.c_str(), "a"); + fprintf(random_seed_file, "%u\n", random_seed); + fclose(random_seed_file); + random_seed_file = nullptr; + + uint16_t seq_num = 0; + uint32_t timestamp = random.Rand<uint32_t>(); + const uint32_t media_ssrc = random.Rand(1u, 0xfffffffe); + uint32_t fec_ssrc; + uint16_t fec_seq_num_offset; + if (use_flexfec) { + fec_ssrc = random.Rand(1u, 0xfffffffe); + fec_seq_num_offset = random.Rand(0, 1 << 15); + } else { + fec_ssrc = media_ssrc; + fec_seq_num_offset = 0; + } + + std::unique_ptr<ForwardErrorCorrection> fec; + if (use_flexfec) { + fec = ForwardErrorCorrection::CreateFlexfec(fec_ssrc, media_ssrc); + } else { + RTC_DCHECK_EQ(media_ssrc, fec_ssrc); + fec = ForwardErrorCorrection::CreateUlpfec(fec_ssrc); + } + + // Loop over the mask types: random and bursty. + for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes; + ++mask_type_idx) { + for (uint32_t loss_rate_idx = 0; loss_rate_idx < loss_rate_size; + ++loss_rate_idx) { + printf("Loss rate: %.2f, Mask type %d \n", loss_rate[loss_rate_idx], + mask_type_idx); + + const uint32_t packet_mask_max = kMaxMediaPackets[mask_type_idx]; + std::unique_ptr<uint8_t[]> packet_mask( + new uint8_t[packet_mask_max * kNumMaskBytesL1]); + + FecMaskType fec_mask_type = kMaskTypes[mask_type_idx]; + + for (uint32_t num_media_packets = 1; num_media_packets <= packet_mask_max; + num_media_packets++) { + internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); + + for (uint32_t num_fec_packets = 1; + num_fec_packets <= num_media_packets && + num_fec_packets <= packet_mask_max; + num_fec_packets++) { + // Loop over num_imp_packets: usually <= (0.3*num_media_packets). + // For this test we check up to ~ (num_media_packets / 4). + uint32_t max_num_imp_packets = num_media_packets / 4 + 1; + for (uint32_t num_imp_packets = 0; + num_imp_packets <= max_num_imp_packets && + num_imp_packets <= packet_mask_max; + num_imp_packets++) { + uint8_t protection_factor = + static_cast<uint8_t>(num_fec_packets * 255 / num_media_packets); + + const uint32_t mask_bytes_per_fec_packet = + (num_media_packets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0; + + memset(packet_mask.get(), 0, + num_media_packets * mask_bytes_per_fec_packet); + + // Transfer packet masks from bit-mask to byte-mask. + internal::GeneratePacketMasks(num_media_packets, num_fec_packets, + num_imp_packets, + kUseUnequalProtection, + mask_table, packet_mask.get()); + +#ifdef VERBOSE_OUTPUT + printf( + "%u media packets, %u FEC packets, %u num_imp_packets, " + "loss rate = %.2f \n", + num_media_packets, num_fec_packets, num_imp_packets, + loss_rate[loss_rate_idx]); + printf("Packet mask matrix \n"); +#endif + + for (uint32_t i = 0; i < num_fec_packets; i++) { + for (uint32_t j = 0; j < num_media_packets; j++) { + const uint8_t byte_mask = + packet_mask[i * mask_bytes_per_fec_packet + j / 8]; + const uint32_t bit_position = (7 - j % 8); + fec_packet_masks[i][j] = + (byte_mask & (1 << bit_position)) >> bit_position; +#ifdef VERBOSE_OUTPUT + printf("%u ", fec_packet_masks[i][j]); +#endif + } +#ifdef VERBOSE_OUTPUT + printf("\n"); +#endif + } +#ifdef VERBOSE_OUTPUT + printf("\n"); +#endif + // Check for all zero rows or columns: indicates incorrect mask. + uint32_t row_limit = num_media_packets; + for (uint32_t i = 0; i < num_fec_packets; ++i) { + uint32_t row_sum = 0; + for (uint32_t j = 0; j < row_limit; ++j) { + row_sum += fec_packet_masks[i][j]; + } + ASSERT_NE(0u, row_sum) << "Row is all zero " << i; + } + for (uint32_t j = 0; j < row_limit; ++j) { + uint32_t column_sum = 0; + for (uint32_t i = 0; i < num_fec_packets; ++i) { + column_sum += fec_packet_masks[i][j]; + } + ASSERT_NE(0u, column_sum) << "Column is all zero " << j; + } + + // Construct media packets. + // Reset the sequence number here for each FEC code/mask tested + // below, to avoid sequence number wrap-around. In actual decoding, + // old FEC packets in list are dropped if sequence number wrap + // around is detected. This case is currently not handled below. + seq_num = 0; + for (uint32_t i = 0; i < num_media_packets; ++i) { + std::unique_ptr<ForwardErrorCorrection::Packet> media_packet( + new ForwardErrorCorrection::Packet()); + const uint32_t kMinPacketSize = 12; + const uint32_t kMaxPacketSize = static_cast<uint32_t>( + IP_PACKET_SIZE - 12 - 28 - fec->MaxPacketOverhead()); + media_packet->length = random.Rand(kMinPacketSize, + kMaxPacketSize); + + // Generate random values for the first 2 bytes. + media_packet->data[0] = random.Rand<uint8_t>(); + media_packet->data[1] = random.Rand<uint8_t>(); + + // The first two bits are assumed to be 10 by the + // FEC encoder. In fact the FEC decoder will set the + // two first bits to 10 regardless of what they + // actually were. Set the first two bits to 10 + // so that a memcmp can be performed for the + // whole restored packet. + media_packet->data[0] |= 0x80; + media_packet->data[0] &= 0xbf; + + // FEC is applied to a whole frame. + // A frame is signaled by multiple packets without + // the marker bit set followed by the last packet of + // the frame for which the marker bit is set. + // Only push one (fake) frame to the FEC. + media_packet->data[1] &= 0x7f; + + ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2], + seq_num); + ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4], + timestamp); + ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], + media_ssrc); + // Generate random values for payload + for (size_t j = 12; j < media_packet->length; ++j) { + media_packet->data[j] = random.Rand<uint8_t>(); + } + media_packet_list.push_back(std::move(media_packet)); + seq_num++; + } + media_packet_list.back()->data[1] |= 0x80; + + ASSERT_EQ(0, fec->EncodeFec(media_packet_list, protection_factor, + num_imp_packets, kUseUnequalProtection, + fec_mask_type, &fec_packet_list)) + << "EncodeFec() failed"; + + ASSERT_EQ(num_fec_packets, fec_packet_list.size()) + << "We requested " << num_fec_packets << " FEC packets, but " + << "EncodeFec() produced " << fec_packet_list.size(); + + memset(media_loss_mask, 0, sizeof(media_loss_mask)); + uint32_t media_packet_idx = 0; + for (const auto& media_packet : media_packet_list) { + // We want a value between 0 and 1. + const float loss_random_variable = random.Rand<float>(); + + if (loss_random_variable >= loss_rate[loss_rate_idx]) { + media_loss_mask[media_packet_idx] = 1; + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> + received_packet( + new ForwardErrorCorrection::ReceivedPacket()); + received_packet->pkt = new ForwardErrorCorrection::Packet(); + received_packet->pkt->length = media_packet->length; + memcpy(received_packet->pkt->data, media_packet->data, + media_packet->length); + received_packet->ssrc = media_ssrc; + received_packet->seq_num = + ByteReader<uint16_t>::ReadBigEndian(&media_packet->data[2]); + received_packet->is_fec = false; + received_packet_list.push_back(std::move(received_packet)); + } + media_packet_idx++; + } + + memset(fec_loss_mask, 0, sizeof(fec_loss_mask)); + uint32_t fec_packet_idx = 0; + for (auto* fec_packet : fec_packet_list) { + const float loss_random_variable = random.Rand<float>(); + if (loss_random_variable >= loss_rate[loss_rate_idx]) { + fec_loss_mask[fec_packet_idx] = 1; + std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> + received_packet( + new ForwardErrorCorrection::ReceivedPacket()); + received_packet->pkt = new ForwardErrorCorrection::Packet(); + received_packet->pkt->length = fec_packet->length; + memcpy(received_packet->pkt->data, fec_packet->data, + fec_packet->length); + received_packet->seq_num = fec_seq_num_offset + seq_num; + received_packet->is_fec = true; + received_packet->ssrc = fec_ssrc; + received_packet_list.push_back(std::move(received_packet)); + + fec_mask_list.push_back(fec_packet_masks[fec_packet_idx]); + } + ++fec_packet_idx; + ++seq_num; + } + +#ifdef VERBOSE_OUTPUT + printf("Media loss mask:\n"); + for (uint32_t i = 0; i < num_media_packets; i++) { + printf("%u ", media_loss_mask[i]); + } + printf("\n\n"); + + printf("FEC loss mask:\n"); + for (uint32_t i = 0; i < num_fec_packets; i++) { + printf("%u ", fec_loss_mask[i]); + } + printf("\n\n"); +#endif + + auto fec_mask_it = fec_mask_list.begin(); + while (fec_mask_it != fec_mask_list.end()) { + uint32_t hamming_dist = 0; + uint32_t recovery_position = 0; + for (uint32_t i = 0; i < num_media_packets; i++) { + if (media_loss_mask[i] == 0 && (*fec_mask_it)[i] == 1) { + recovery_position = i; + ++hamming_dist; + } + } + auto item_to_delete = fec_mask_it; + ++fec_mask_it; + + if (hamming_dist == 1) { + // Recovery possible. Restart search. + media_loss_mask[recovery_position] = 1; + fec_mask_it = fec_mask_list.begin(); + } else if (hamming_dist == 0) { + // FEC packet cannot provide further recovery. + fec_mask_list.erase(item_to_delete); + } + } +#ifdef VERBOSE_OUTPUT + printf("Recovery mask:\n"); + for (uint32_t i = 0; i < num_media_packets; ++i) { + printf("%u ", media_loss_mask[i]); + } + printf("\n\n"); +#endif + // For error-checking frame completion. + bool fec_packet_received = false; + while (!received_packet_list.empty()) { + size_t num_packets_to_decode = random.Rand( + 1u, static_cast<uint32_t>(received_packet_list.size())); + ReceivePackets(&to_decode_list, &received_packet_list, + num_packets_to_decode, reorder_rate, + duplicate_rate, &random); + + if (fec_packet_received == false) { + for (const auto& received_packet : to_decode_list) { + if (received_packet->is_fec) { + fec_packet_received = true; + } + } + } + for (const auto& received_packet : to_decode_list) { + fec->DecodeFec(*received_packet, &recovered_packet_list); + } + to_decode_list.clear(); + } + media_packet_idx = 0; + for (const auto& media_packet : media_packet_list) { + if (media_loss_mask[media_packet_idx] == 1) { + // Should have recovered this packet. + auto recovered_packet_list_it = recovered_packet_list.cbegin(); + + ASSERT_FALSE(recovered_packet_list_it == + recovered_packet_list.end()) + << "Insufficient number of recovered packets."; + ForwardErrorCorrection::RecoveredPacket* recovered_packet = + recovered_packet_list_it->get(); + + ASSERT_EQ(recovered_packet->pkt->length, media_packet->length) + << "Recovered packet length not identical to original " + << "media packet"; + ASSERT_EQ(0, memcmp(recovered_packet->pkt->data, + media_packet->data, media_packet->length)) + << "Recovered packet payload not identical to original " + << "media packet"; + recovered_packet_list.pop_front(); + } + ++media_packet_idx; + } + fec->ResetState(&recovered_packet_list); + ASSERT_TRUE(recovered_packet_list.empty()) + << "Excessive number of recovered packets.\t size is: " + << recovered_packet_list.size(); + // -- Teardown -- + media_packet_list.clear(); + + // Clear FEC packet list, so we don't pass in a non-empty + // list in the next call to DecodeFec(). + fec_packet_list.clear(); + + // Delete received packets we didn't pass to DecodeFec(), due to + // early frame completion. + received_packet_list.clear(); + + while (!fec_mask_list.empty()) { + fec_mask_list.pop_front(); + } + timestamp += 90000 / 30; + } // loop over num_imp_packets + } // loop over FecPackets + } // loop over num_media_packets + } // loop over loss rates + } // loop over mask types + + // Have DecodeFec clear the recovered packet list. + fec->ResetState(&recovered_packet_list); + ASSERT_TRUE(recovered_packet_list.empty()) + << "Recovered packet list is not empty"; +} + +TEST(FecTest, UlpfecTest) { + RunTest(false); +} + +TEST(FecTest, FlexfecTest) { + RunTest(true); +} + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_packet_masks_metrics.cc b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_packet_masks_metrics.cc new file mode 100644 index 0000000000..f40a8e8ed6 --- /dev/null +++ b/third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_packet_masks_metrics.cc @@ -0,0 +1,1081 @@ +/* + * 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. + */ + +/* + * The purpose of this test is to compute metrics to characterize the properties + * and efficiency of the packets masks used in the generic XOR FEC code. + * + * The metrics measure the efficiency (recovery potential or residual loss) of + * the FEC code, under various statistical loss models for the packet/symbol + * loss events. Various constraints on the behavior of these metrics are + * verified, and compared to the reference RS (Reed-Solomon) code. This serves + * in some way as a basic check/benchmark for the packet masks. + * + * By an FEC code, we mean an erasure packet/symbol code, characterized by: + * (1) The code size parameters (k,m), where k = number of source/media packets, + * and m = number of FEC packets, + * (2) The code type: XOR or RS. + * In the case of XOR, the residual loss is determined via the set of packet + * masks (generator matrix). In the case of RS, the residual loss is determined + * directly from the MDS (maximum distance separable) property of RS. + * + * Currently two classes of packets masks are available (random type and bursty + * type), so three codes are considered below: RS, XOR-random, and XOR-bursty. + * The bursty class is defined up to k=12, so (k=12,m=12) is largest code size + * considered in this test. + * + * The XOR codes are defined via the RFC 5109 and correspond to the class of + * LDGM (low density generator matrix) codes, which is a subset of the LDPC + * (low density parity check) codes. Future implementation will consider + * extending our XOR codes to include LDPC codes, which explicitly include + * protection of FEC packets. + * + * The type of packet/symbol loss models considered in this test are: + * (1) Random loss: Bernoulli process, characterized by the average loss rate. + * (2) Bursty loss: Markov chain (Gilbert-Elliot model), characterized by two + * parameters: average loss rate and average burst length. +*/ + +#include <math.h> + +#include <memory> + +#include "modules/rtp_rtcp/source/forward_error_correction_internal.h" +#include "modules/rtp_rtcp/test/testFec/average_residual_loss_xor_codes.h" +#include "test/gtest.h" +#include "test/testsupport/fileutils.h" + +namespace webrtc { + +// Maximum number of media packets allows for XOR (RFC 5109) code. +enum { kMaxNumberMediaPackets = 48 }; + +// Maximum number of media packets allowed for each mask type. +const uint16_t kMaxMediaPackets[] = {kMaxNumberMediaPackets, 12}; + +// Maximum gap size for characterizing the consecutiveness of the loss. +const int kMaxGapSize = 2 * kMaxMediaPacketsTest; + +// Number of gap levels written to file/output. +const int kGapSizeOutput = 5; + +// Maximum number of states for characterizing the residual loss distribution. +const int kNumStatesDistribution = 2 * kMaxMediaPacketsTest * kMaxGapSize + 1; + +// The code type. +enum CodeType { + xor_random_code, // XOR with random mask type. + xor_bursty_code, // XOR with bursty mask type. + rs_code // Reed_solomon. +}; + +// The code size parameters. +struct CodeSizeParams { + int num_media_packets; + int num_fec_packets; + // Protection level: num_fec_packets / (num_media_packets + num_fec_packets). + float protection_level; + // Number of loss configurations, for a given loss number and gap number. + // The gap number refers to the maximum gap/hole of a loss configuration + // (used to measure the "consecutiveness" of the loss). + int configuration_density[kNumStatesDistribution]; +}; + +// The type of loss models. +enum LossModelType { + kRandomLossModel, + kBurstyLossModel +}; + +struct LossModel { + LossModelType loss_type; + float average_loss_rate; + float average_burst_length; +}; + +// Average loss rates. +const float kAverageLossRate[] = { 0.025f, 0.05f, 0.1f, 0.25f }; + +// Average burst lengths. The case of |kAverageBurstLength = 1.0| refers to +// the random model. Note that for the random (Bernoulli) model, the average +// burst length is determined by the average loss rate, i.e., +// AverageBurstLength = 1 / (1 - AverageLossRate) for random model. +const float kAverageBurstLength[] = { 1.0f, 2.0f, 4.0f }; + +// Total number of loss models: For each burst length case, there are +// a number of models corresponding to the loss rates. +const int kNumLossModels = (sizeof(kAverageBurstLength) / + sizeof(*kAverageBurstLength)) * (sizeof(kAverageLossRate) / + sizeof(*kAverageLossRate)); + +// Thresholds on the average loss rate of the packet loss model, below which +// certain properties of the codes are expected. +float loss_rate_upper_threshold = 0.20f; +float loss_rate_lower_threshold = 0.025f; + +// Set of thresholds on the expected average recovery rate, for each code type. +// These are global thresholds for now; in future version we may condition them +// on the code length/size and protection level. +const float kRecoveryRateXorRandom[3] = { 0.94f, 0.50f, 0.19f }; +const float kRecoveryRateXorBursty[3] = { 0.90f, 0.54f, 0.22f }; + +// Metrics for a given FEC code; each code is defined by the code type +// (RS, XOR-random/bursty), and the code size parameters (k,m), where +// k = num_media_packets, m = num_fec_packets. +struct MetricsFecCode { + // The average and variance of the residual loss, as a function of the + // packet/symbol loss model. The average/variance is computed by averaging + // over all loss configurations wrt the loss probability given by the + // underlying loss model. + double average_residual_loss[kNumLossModels]; + double variance_residual_loss[kNumLossModels]; + // The residual loss, as a function of the loss number and the gap number of + // the loss configurations. The gap number refers to the maximum gap/hole of + // a loss configuration (used to measure the "consecutiveness" of the loss). + double residual_loss_per_loss_gap[kNumStatesDistribution]; + // The recovery rate as a function of the loss number. + double recovery_rate_per_loss[2 * kMaxMediaPacketsTest + 1]; +}; + +MetricsFecCode kMetricsXorRandom[kNumberCodes]; +MetricsFecCode kMetricsXorBursty[kNumberCodes]; +MetricsFecCode kMetricsReedSolomon[kNumberCodes]; + +class FecPacketMaskMetricsTest : public ::testing::Test { + protected: + FecPacketMaskMetricsTest() { } + + int max_num_codes_; + LossModel loss_model_[kNumLossModels]; + CodeSizeParams code_params_[kNumberCodes]; + + uint8_t fec_packet_masks_[kMaxNumberMediaPackets][kMaxNumberMediaPackets]; + FILE* fp_mask_; + + // Measure of the gap of the loss for configuration given by |state|. + // This is to measure degree of consecutiveness for the loss configuration. + // Useful if the packets are sent out in order of sequence numbers and there + // is little/no re-ordering during transmission. + int GapLoss(int tot_num_packets, uint8_t* state) { + int max_gap_loss = 0; + // Find the first loss. + int first_loss = 0; + for (int i = 0; i < tot_num_packets; i++) { + if (state[i] == 1) { + first_loss = i; + break; + } + } + int prev_loss = first_loss; + for (int i = first_loss + 1; i < tot_num_packets; i++) { + if (state[i] == 1) { // Lost state. + int gap_loss = (i - prev_loss) - 1; + if (gap_loss > max_gap_loss) { + max_gap_loss = gap_loss; + } + prev_loss = i; + } + } + return max_gap_loss; + } + + // Returns the number of recovered media packets for the XOR code, given the + // packet mask |fec_packet_masks_|, for the loss state/configuration given by + // |state|. + int RecoveredMediaPackets(int num_media_packets, + int num_fec_packets, + uint8_t* state) { + std::unique_ptr<uint8_t[]> state_tmp( + new uint8_t[num_media_packets + num_fec_packets]); + memcpy(state_tmp.get(), state, num_media_packets + num_fec_packets); + int num_recovered_packets = 0; + bool loop_again = true; + while (loop_again) { + loop_again = false; + bool recovered_new_packet = false; + // Check if we can recover anything: loop over all possible FEC packets. + for (int i = 0; i < num_fec_packets; i++) { + if (state_tmp[i + num_media_packets] == 0) { + // We have this FEC packet. + int num_packets_in_mask = 0; + int num_received_packets_in_mask = 0; + for (int j = 0; j < num_media_packets; j++) { + if (fec_packet_masks_[i][j] == 1) { + num_packets_in_mask++; + if (state_tmp[j] == 0) { + num_received_packets_in_mask++; + } + } + } + if ((num_packets_in_mask - 1) == num_received_packets_in_mask) { + // We can recover the missing media packet for this FEC packet. + num_recovered_packets++; + recovered_new_packet = true; + int jsel = -1; + int check_num_recovered = 0; + // Update the state with newly recovered media packet. + for (int j = 0; j < num_media_packets; j++) { + if (fec_packet_masks_[i][j] == 1 && state_tmp[j] == 1) { + // This is the lost media packet we will recover. + jsel = j; + check_num_recovered++; + } + } + // Check that we can only recover 1 packet. + assert(check_num_recovered == 1); + // Update the state with the newly recovered media packet. + state_tmp[jsel] = 0; + } + } + } // Go to the next FEC packet in the loop. + // If we have recovered at least one new packet in this FEC loop, + // go through loop again, otherwise we leave loop. + if (recovered_new_packet) { + loop_again = true; + } + } + return num_recovered_packets; + } + + // Compute the probability of occurence of the loss state/configuration, + // given by |state|, for all the loss models considered in this test. + void ComputeProbabilityWeight(double* prob_weight, + uint8_t* state, + int tot_num_packets) { + // Loop over the loss models. + for (int k = 0; k < kNumLossModels; k++) { + double loss_rate = static_cast<double>( + loss_model_[k].average_loss_rate); + double burst_length = static_cast<double>( + loss_model_[k].average_burst_length); + double result = 1.0; + if (loss_model_[k].loss_type == kRandomLossModel) { + for (int i = 0; i < tot_num_packets; i++) { + if (state[i] == 0) { + result *= (1.0 - loss_rate); + } else { + result *= loss_rate; + } + } + } else { // Gilbert-Elliot model for burst model. + assert(loss_model_[k].loss_type == kBurstyLossModel); + // Transition probabilities: from previous to current state. + // Prob. of previous = lost --> current = received. + double prob10 = 1.0 / burst_length; + // Prob. of previous = lost --> currrent = lost. + double prob11 = 1.0 - prob10; + // Prob. of previous = received --> current = lost. + double prob01 = prob10 * (loss_rate / (1.0 - loss_rate)); + // Prob. of previous = received --> current = received. + double prob00 = 1.0 - prob01; + + // Use stationary probability for first state/packet. + if (state[0] == 0) { // Received + result = (1.0 - loss_rate); + } else { // Lost + result = loss_rate; + } + + // Subsequent states: use transition probabilities. + for (int i = 1; i < tot_num_packets; i++) { + // Current state is received + if (state[i] == 0) { + if (state[i-1] == 0) { + result *= prob00; // Previous received, current received. + } else { + result *= prob10; // Previous lost, current received. + } + } else { // Current state is lost + if (state[i-1] == 0) { + result *= prob01; // Previous received, current lost. + } else { + result *= prob11; // Previous lost, current lost. + } + } + } + } + prob_weight[k] = result; + } + } + + void CopyMetrics(MetricsFecCode* metrics_output, + MetricsFecCode metrics_input) { + memcpy(metrics_output->average_residual_loss, + metrics_input.average_residual_loss, + sizeof(double) * kNumLossModels); + memcpy(metrics_output->variance_residual_loss, + metrics_input.variance_residual_loss, + sizeof(double) * kNumLossModels); + memcpy(metrics_output->residual_loss_per_loss_gap, + metrics_input.residual_loss_per_loss_gap, + sizeof(double) * kNumStatesDistribution); + memcpy(metrics_output->recovery_rate_per_loss, + metrics_input.recovery_rate_per_loss, + sizeof(double) * 2 * kMaxMediaPacketsTest); + } + + // Compute the residual loss per gap, by summing the + // |residual_loss_per_loss_gap| over all loss configurations up to loss number + // = |num_fec_packets|. + double ComputeResidualLossPerGap(MetricsFecCode metrics, + int gap_number, + int num_fec_packets, + int code_index) { + double residual_loss_gap = 0.0; + int tot_num_configs = 0; + for (int loss = 1; loss <= num_fec_packets; loss++) { + int index = gap_number * (2 * kMaxMediaPacketsTest) + loss; + residual_loss_gap += metrics.residual_loss_per_loss_gap[index]; + tot_num_configs += + code_params_[code_index].configuration_density[index]; + } + // Normalize, to compare across code sizes. + if (tot_num_configs > 0) { + residual_loss_gap = residual_loss_gap / + static_cast<double>(tot_num_configs); + } + return residual_loss_gap; + } + + // Compute the recovery rate per loss number, by summing the + // |residual_loss_per_loss_gap| over all gap configurations. + void ComputeRecoveryRatePerLoss(MetricsFecCode* metrics, + int num_media_packets, + int num_fec_packets, + int code_index) { + for (int loss = 1; loss <= num_media_packets + num_fec_packets; loss++) { + metrics->recovery_rate_per_loss[loss] = 0.0; + int tot_num_configs = 0; + double arl = 0.0; + for (int gap = 0; gap < kMaxGapSize; gap ++) { + int index = gap * (2 * kMaxMediaPacketsTest) + loss; + arl += metrics->residual_loss_per_loss_gap[index]; + tot_num_configs += + code_params_[code_index].configuration_density[index]; + } + // Normalize, to compare across code sizes. + if (tot_num_configs > 0) { + arl = arl / static_cast<double>(tot_num_configs); + } + // Recovery rate for a given loss |loss| is 1 minus the scaled |arl|, + // where the scale factor is relative to code size/parameters. + double scaled_loss = static_cast<double>(loss * num_media_packets) / + static_cast<double>(num_media_packets + num_fec_packets); + metrics->recovery_rate_per_loss[loss] = 1.0 - arl / scaled_loss; + } + } + + void SetMetricsZero(MetricsFecCode* metrics) { + memset(metrics->average_residual_loss, 0, sizeof(double) * kNumLossModels); + memset(metrics->variance_residual_loss, 0, sizeof(double) * kNumLossModels); + memset(metrics->residual_loss_per_loss_gap, 0, + sizeof(double) * kNumStatesDistribution); + memset(metrics->recovery_rate_per_loss, 0, + sizeof(double) * 2 * kMaxMediaPacketsTest + 1); + } + + // Compute the metrics for an FEC code, given by the code type |code_type| + // (XOR-random/ bursty or RS), and by the code index |code_index| + // (which containes the code size parameters/protection length). + void ComputeMetricsForCode(CodeType code_type, + int code_index) { + std::unique_ptr<double[]> prob_weight(new double[kNumLossModels]); + memset(prob_weight.get() , 0, sizeof(double) * kNumLossModels); + MetricsFecCode metrics_code; + SetMetricsZero(&metrics_code); + + int num_media_packets = code_params_[code_index].num_media_packets; + int num_fec_packets = code_params_[code_index].num_fec_packets; + int tot_num_packets = num_media_packets + num_fec_packets; + std::unique_ptr<uint8_t[]> state(new uint8_t[tot_num_packets]); + memset(state.get() , 0, tot_num_packets); + + int num_loss_configurations = static_cast<int>(pow(2.0f, tot_num_packets)); + // Loop over all loss configurations for the symbol sequence of length + // |tot_num_packets|. In this version we process up to (k=12, m=12) codes, + // and get exact expressions for the residual loss. + // TODO(marpan): For larger codes, loop over some random sample of loss + // configurations, sampling driven by the underlying statistical loss model + // (importance sampling). + + // The symbols/packets are arranged as a sequence of source/media packets + // followed by FEC packets. This is the sequence ordering used in the RTP. + // A configuration refers to a sequence of received/lost (0/1 bit) states + // for the string of packets/symbols. For example, for a (k=4,m=3) code + // (4 media packets, 3 FEC packets), with 2 losses (one media and one FEC), + // the loss configurations is: + // Media1 Media2 Media3 Media4 FEC1 FEC2 FEC3 + // 0 0 1 0 0 1 0 + for (int i = 1; i < num_loss_configurations; i++) { + // Counter for number of packets lost. + int num_packets_lost = 0; + // Counters for the number of media packets lost. + int num_media_packets_lost = 0; + + // Map configuration number to a loss state. + for (int j = 0; j < tot_num_packets; j++) { + state[j] = 0; // Received state. + int bit_value = i >> (tot_num_packets - j - 1) & 1; + if (bit_value == 1) { + state[j] = 1; // Lost state. + num_packets_lost++; + if (j < num_media_packets) { + num_media_packets_lost++; + } + } + } // Done with loop over total number of packets. + assert(num_media_packets_lost <= num_media_packets); + assert(num_packets_lost <= tot_num_packets && num_packets_lost > 0); + double residual_loss = 0.0; + // Only need to compute residual loss (number of recovered packets) for + // configurations that have at least one media packet lost. + if (num_media_packets_lost >= 1) { + // Compute the number of recovered packets. + int num_recovered_packets = 0; + if (code_type == xor_random_code || code_type == xor_bursty_code) { + num_recovered_packets = RecoveredMediaPackets(num_media_packets, + num_fec_packets, + state.get()); + } else { + // For the RS code, we can either completely recover all the packets + // if the loss is less than or equal to the number of FEC packets, + // otherwise we can recover none of the missing packets. This is the + // all or nothing (MDS) property of the RS code. + if (num_packets_lost <= num_fec_packets) { + num_recovered_packets = num_media_packets_lost; + } + } + assert(num_recovered_packets <= num_media_packets); + // Compute the residual loss. We only care about recovering media/source + // packets, so residual loss is based on lost/recovered media packets. + residual_loss = static_cast<double>(num_media_packets_lost - + num_recovered_packets); + // Compute the probability weights for this configuration. + ComputeProbabilityWeight(prob_weight.get(), + state.get(), + tot_num_packets); + // Update the average and variance of the residual loss. + for (int k = 0; k < kNumLossModels; k++) { + metrics_code.average_residual_loss[k] += residual_loss * + prob_weight[k]; + metrics_code.variance_residual_loss[k] += residual_loss * + residual_loss * prob_weight[k]; + } + } // Done with processing for num_media_packets_lost >= 1. + // Update the distribution statistics. + // Compute the gap of the loss (the "consecutiveness" of the loss). + int gap_loss = GapLoss(tot_num_packets, state.get()); + assert(gap_loss < kMaxGapSize); + int index = gap_loss * (2 * kMaxMediaPacketsTest) + num_packets_lost; + assert(index < kNumStatesDistribution); + metrics_code.residual_loss_per_loss_gap[index] += residual_loss; + if (code_type == xor_random_code) { + // The configuration density is only a function of the code length and + // only needs to computed for the first |code_type| passed here. + code_params_[code_index].configuration_density[index]++; + } + } // Done with loop over configurations. + // Normalize the average residual loss and compute/normalize the variance. + for (int k = 0; k < kNumLossModels; k++) { + // Normalize the average residual loss by the total number of packets + // |tot_num_packets| (i.e., the code length). For a code with no (zero) + // recovery, the average residual loss for that code would be reduced like + // ~|average_loss_rate| * |num_media_packets| / |tot_num_packets|. This is + // the expected reduction in the average residual loss just from adding + // FEC packets to the symbol sequence. + metrics_code.average_residual_loss[k] = + metrics_code.average_residual_loss[k] / + static_cast<double>(tot_num_packets); + metrics_code.variance_residual_loss[k] = + metrics_code.variance_residual_loss[k] / + static_cast<double>(num_media_packets * num_media_packets); + metrics_code.variance_residual_loss[k] = + metrics_code.variance_residual_loss[k] - + (metrics_code.average_residual_loss[k] * + metrics_code.average_residual_loss[k]); + assert(metrics_code.variance_residual_loss[k] >= 0.0); + assert(metrics_code.average_residual_loss[k] > 0.0); + metrics_code.variance_residual_loss[k] = + sqrt(metrics_code.variance_residual_loss[k]) / + metrics_code.average_residual_loss[k]; + } + + // Compute marginal distribution as a function of loss parameter. + ComputeRecoveryRatePerLoss(&metrics_code, + num_media_packets, + num_fec_packets, + code_index); + if (code_type == rs_code) { + CopyMetrics(&kMetricsReedSolomon[code_index], metrics_code); + } else if (code_type == xor_random_code) { + CopyMetrics(&kMetricsXorRandom[code_index], metrics_code); + } else if (code_type == xor_bursty_code) { + CopyMetrics(&kMetricsXorBursty[code_index], metrics_code); + } else { + assert(false); + } + } + + void WriteOutMetricsAllFecCodes() { + std::string filename = test::OutputPath() + "data_metrics_all_codes"; + FILE* fp = fopen(filename.c_str(), "wb"); + // Loop through codes up to |kMaxMediaPacketsTest|. + int code_index = 0; + for (int num_media_packets = 1; num_media_packets <= kMaxMediaPacketsTest; + num_media_packets++) { + for (int num_fec_packets = 1; num_fec_packets <= num_media_packets; + num_fec_packets++) { + fprintf(fp, "FOR CODE: (%d, %d) \n", num_media_packets, + num_fec_packets); + for (int k = 0; k < kNumLossModels; k++) { + float loss_rate = loss_model_[k].average_loss_rate; + float burst_length = loss_model_[k].average_burst_length; + fprintf(fp, "Loss rate = %.2f, Burst length = %.2f: %.4f %.4f %.4f" + " **** %.4f %.4f %.4f \n", + loss_rate, + burst_length, + 100 * kMetricsReedSolomon[code_index].average_residual_loss[k], + 100 * kMetricsXorRandom[code_index].average_residual_loss[k], + 100 * kMetricsXorBursty[code_index].average_residual_loss[k], + kMetricsReedSolomon[code_index].variance_residual_loss[k], + kMetricsXorRandom[code_index].variance_residual_loss[k], + kMetricsXorBursty[code_index].variance_residual_loss[k]); + } + for (int gap = 0; gap < kGapSizeOutput; gap ++) { + double rs_residual_loss = ComputeResidualLossPerGap( + kMetricsReedSolomon[code_index], + gap, + num_fec_packets, + code_index); + double xor_random_residual_loss = ComputeResidualLossPerGap( + kMetricsXorRandom[code_index], + gap, + num_fec_packets, + code_index); + double xor_bursty_residual_loss = ComputeResidualLossPerGap( + kMetricsXorBursty[code_index], + gap, + num_fec_packets, + code_index); + fprintf(fp, "Residual loss as a function of gap " + "%d: %.4f %.4f %.4f \n", + gap, + rs_residual_loss, + xor_random_residual_loss, + xor_bursty_residual_loss); + } + fprintf(fp, "Recovery rate as a function of loss number \n"); + for (int loss = 1; loss <= num_media_packets + num_fec_packets; + loss ++) { + fprintf(fp, "For loss number %d: %.4f %.4f %.4f \n", + loss, + kMetricsReedSolomon[code_index]. + recovery_rate_per_loss[loss], + kMetricsXorRandom[code_index]. + recovery_rate_per_loss[loss], + kMetricsXorBursty[code_index]. + recovery_rate_per_loss[loss]); + } + fprintf(fp, "******************\n"); + fprintf(fp, "\n"); + code_index++; + } + } + fclose(fp); + } + + void SetLossModels() { + int num_loss_rates = sizeof(kAverageLossRate) / + sizeof(*kAverageLossRate); + int num_burst_lengths = sizeof(kAverageBurstLength) / + sizeof(*kAverageBurstLength); + int num_loss_models = 0; + for (int k = 0; k < num_burst_lengths; k++) { + for (int k2 = 0; k2 < num_loss_rates; k2++) { + loss_model_[num_loss_models].average_loss_rate = kAverageLossRate[k2]; + loss_model_[num_loss_models].average_burst_length = + kAverageBurstLength[k]; + // First set of loss models are of random type. + if (k == 0) { + loss_model_[num_loss_models].loss_type = kRandomLossModel; + } else { + loss_model_[num_loss_models].loss_type = kBurstyLossModel; + } + num_loss_models++; + } + } + assert(num_loss_models == kNumLossModels); + } + + void SetCodeParams() { + int code_index = 0; + for (int num_media_packets = 1; num_media_packets <= kMaxMediaPacketsTest; + num_media_packets++) { + for (int num_fec_packets = 1; num_fec_packets <= num_media_packets; + num_fec_packets++) { + code_params_[code_index].num_media_packets = num_media_packets; + code_params_[code_index].num_fec_packets = num_fec_packets; + code_params_[code_index].protection_level = + static_cast<float>(num_fec_packets) / + static_cast<float>(num_media_packets + num_fec_packets); + for (int k = 0; k < kNumStatesDistribution; k++) { + code_params_[code_index].configuration_density[k] = 0; + } + code_index++; + } + } + max_num_codes_ = code_index; + } + + // Make some basic checks on the packet masks. Return -1 if any of these + // checks fail. + int RejectInvalidMasks(int num_media_packets, int num_fec_packets) { + // Make sure every FEC packet protects something. + for (int i = 0; i < num_fec_packets; i++) { + int row_degree = 0; + for (int j = 0; j < num_media_packets; j++) { + if (fec_packet_masks_[i][j] == 1) { + row_degree++; + } + } + if (row_degree == 0) { + printf("Invalid mask: FEC packet has empty mask (does not protect " + "anything) %d %d %d \n", i, num_media_packets, num_fec_packets); + return -1; + } + } + // Mask sure every media packet has some protection. + for (int j = 0; j < num_media_packets; j++) { + int column_degree = 0; + for (int i = 0; i < num_fec_packets; i++) { + if (fec_packet_masks_[i][j] == 1) { + column_degree++; + } + } + if (column_degree == 0) { + printf("Invalid mask: Media packet has no protection at all %d %d %d " + "\n", j, num_media_packets, num_fec_packets); + return -1; + } + } + // Make sure we do not have two identical FEC packets. + for (int i = 0; i < num_fec_packets; i++) { + for (int i2 = i + 1; i2 < num_fec_packets; i2++) { + int overlap = 0; + for (int j = 0; j < num_media_packets; j++) { + if (fec_packet_masks_[i][j] == fec_packet_masks_[i2][j]) { + overlap++; + } + } + if (overlap == num_media_packets) { + printf("Invalid mask: Two FEC packets are identical %d %d %d %d \n", + i, i2, num_media_packets, num_fec_packets); + return -1; + } + } + } + // Avoid codes that have two media packets with full protection (all 1s in + // their corresponding columns). This would mean that if we lose those + // two packets, we can never recover them even if we receive all the other + // packets. Exclude the special cases of 1 or 2 FEC packets. + if (num_fec_packets > 2) { + for (int j = 0; j < num_media_packets; j++) { + for (int j2 = j + 1; j2 < num_media_packets; j2++) { + int degree = 0; + for (int i = 0; i < num_fec_packets; i++) { + if (fec_packet_masks_[i][j] == fec_packet_masks_[i][j2] && + fec_packet_masks_[i][j] == 1) { + degree++; + } + } + if (degree == num_fec_packets) { + printf("Invalid mask: Two media packets are have full degree " + "%d %d %d %d \n", j, j2, num_media_packets, num_fec_packets); + return -1; + } + } + } + } + return 0; + } + + void GetPacketMaskConvertToBitMask(uint8_t* packet_mask, + int num_media_packets, + int num_fec_packets, + int mask_bytes_fec_packet, + CodeType code_type) { + for (int i = 0; i < num_fec_packets; i++) { + for (int j = 0; j < num_media_packets; j++) { + const uint8_t byte_mask = + packet_mask[i * mask_bytes_fec_packet + j / 8]; + const int bit_position = (7 - j % 8); + fec_packet_masks_[i][j] = + (byte_mask & (1 << bit_position)) >> bit_position; + fprintf(fp_mask_, "%d ", fec_packet_masks_[i][j]); + } + fprintf(fp_mask_, "\n"); + } + fprintf(fp_mask_, "\n"); + } + + int ProcessXORPacketMasks(CodeType code_type, + FecMaskType fec_mask_type) { + int code_index = 0; + // Maximum number of media packets allowed for the mask type. + const int packet_mask_max = kMaxMediaPackets[fec_mask_type]; + std::unique_ptr<uint8_t[]> packet_mask( + new uint8_t[packet_mask_max * kUlpfecMaxPacketMaskSize]); + // Loop through codes up to |kMaxMediaPacketsTest|. + for (int num_media_packets = 1; num_media_packets <= kMaxMediaPacketsTest; + num_media_packets++) { + const int mask_bytes_fec_packet = + static_cast<int>(internal::PacketMaskSize(num_media_packets)); + internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); + for (int num_fec_packets = 1; num_fec_packets <= num_media_packets; + num_fec_packets++) { + memset(packet_mask.get(), 0, num_media_packets * mask_bytes_fec_packet); + memcpy(packet_mask.get(), + mask_table.fec_packet_mask_table()[num_media_packets - 1] + [num_fec_packets - 1], + num_fec_packets * mask_bytes_fec_packet); + // Convert to bit mask. + GetPacketMaskConvertToBitMask(packet_mask.get(), num_media_packets, + num_fec_packets, mask_bytes_fec_packet, + code_type); + if (RejectInvalidMasks(num_media_packets, num_fec_packets) < 0) { + return -1; + } + // Compute the metrics for this code/mask. + ComputeMetricsForCode(code_type, + code_index); + code_index++; + } + } + assert(code_index == kNumberCodes); + return 0; + } + + void ProcessRS(CodeType code_type) { + int code_index = 0; + for (int num_media_packets = 1; num_media_packets <= kMaxMediaPacketsTest; + num_media_packets++) { + for (int num_fec_packets = 1; num_fec_packets <= num_media_packets; + num_fec_packets++) { + // Compute the metrics for this code type. + ComputeMetricsForCode(code_type, + code_index); + code_index++; + } + } + } + + // Compute metrics for all code types and sizes. + void ComputeMetricsAllCodes() { + SetLossModels(); + SetCodeParams(); + // Get metrics for XOR code with packet masks of random type. + std::string filename = test::OutputPath() + "data_packet_masks"; + fp_mask_ = fopen(filename.c_str(), "wb"); + fprintf(fp_mask_, "MASK OF TYPE RANDOM: \n"); + EXPECT_EQ(ProcessXORPacketMasks(xor_random_code, kFecMaskRandom), 0); + // Get metrics for XOR code with packet masks of bursty type. + fprintf(fp_mask_, "MASK OF TYPE BURSTY: \n"); + EXPECT_EQ(ProcessXORPacketMasks(xor_bursty_code, kFecMaskBursty), 0); + fclose(fp_mask_); + // Get metrics for Reed-Solomon code. + ProcessRS(rs_code); + } +}; + +// Verify that the average residual loss, averaged over loss models +// appropriate to each mask type, is below some maximum acceptable level. The +// acceptable levels are read in from a file, and correspond to a current set +// of packet masks. The levels for each code may be updated over time. +TEST_F(FecPacketMaskMetricsTest, FecXorMaxResidualLoss) { + SetLossModels(); + SetCodeParams(); + ComputeMetricsAllCodes(); + WriteOutMetricsAllFecCodes(); + int num_loss_rates = sizeof(kAverageLossRate) / + sizeof(*kAverageLossRate); + int num_burst_lengths = sizeof(kAverageBurstLength) / + sizeof(*kAverageBurstLength); + for (int code_index = 0; code_index < max_num_codes_; code_index++) { + double sum_residual_loss_random_mask_random_loss = 0.0; + double sum_residual_loss_bursty_mask_bursty_loss = 0.0; + // Compute the sum residual loss across the models, for each mask type. + for (int k = 0; k < kNumLossModels; k++) { + if (loss_model_[k].loss_type == kRandomLossModel) { + sum_residual_loss_random_mask_random_loss += + kMetricsXorRandom[code_index].average_residual_loss[k]; + } else if (loss_model_[k].loss_type == kBurstyLossModel) { + sum_residual_loss_bursty_mask_bursty_loss += + kMetricsXorBursty[code_index].average_residual_loss[k]; + } + } + float average_residual_loss_random_mask_random_loss = + sum_residual_loss_random_mask_random_loss / num_loss_rates; + float average_residual_loss_bursty_mask_bursty_loss = + sum_residual_loss_bursty_mask_bursty_loss / + (num_loss_rates * (num_burst_lengths - 1)); + const float ref_random_mask = kMaxResidualLossRandomMask[code_index]; + const float ref_bursty_mask = kMaxResidualLossBurstyMask[code_index]; + EXPECT_LE(average_residual_loss_random_mask_random_loss, ref_random_mask); + EXPECT_LE(average_residual_loss_bursty_mask_bursty_loss, ref_bursty_mask); + } +} + +// Verify the behavior of the XOR codes vs the RS codes. +// For random loss model with average loss rates <= the code protection level, +// the RS code (optimal MDS code) is more efficient than XOR codes. +// However, for larger loss rates (above protection level) and/or bursty +// loss models, the RS is not always more efficient than XOR (though in most +// cases it still is). +TEST_F(FecPacketMaskMetricsTest, FecXorVsRS) { + SetLossModels(); + SetCodeParams(); + for (int code_index = 0; code_index < max_num_codes_; code_index++) { + for (int k = 0; k < kNumLossModels; k++) { + float loss_rate = loss_model_[k].average_loss_rate; + float protection_level = code_params_[code_index].protection_level; + // Under these conditions we expect XOR to not be better than RS. + if (loss_model_[k].loss_type == kRandomLossModel && + loss_rate <= protection_level) { + EXPECT_GE(kMetricsXorRandom[code_index].average_residual_loss[k], + kMetricsReedSolomon[code_index].average_residual_loss[k]); + EXPECT_GE(kMetricsXorBursty[code_index].average_residual_loss[k], + kMetricsReedSolomon[code_index].average_residual_loss[k]); + } + // TODO(marpan): There are some cases (for high loss rates and/or + // burst loss models) where XOR is better than RS. Is there some pattern + // we can identify and enforce as a constraint? + } + } +} + +// Verify the trend (change) in the average residual loss, as a function of +// loss rate, of the XOR code relative to the RS code. +// The difference between XOR and RS should not get worse as we increase +// the average loss rate. +TEST_F(FecPacketMaskMetricsTest, FecTrendXorVsRsLossRate) { + SetLossModels(); + SetCodeParams(); + // TODO(marpan): Examine this further to see if the condition can be strictly + // satisfied (i.e., scale = 1.0) for all codes with different/better masks. + double scale = 0.90; + int num_loss_rates = sizeof(kAverageLossRate) / + sizeof(*kAverageLossRate); + int num_burst_lengths = sizeof(kAverageBurstLength) / + sizeof(*kAverageBurstLength); + for (int code_index = 0; code_index < max_num_codes_; code_index++) { + for (int i = 0; i < num_burst_lengths; i++) { + for (int j = 0; j < num_loss_rates - 1; j++) { + int k = num_loss_rates * i + j; + // For XOR random. + if (kMetricsXorRandom[code_index].average_residual_loss[k] > + kMetricsReedSolomon[code_index].average_residual_loss[k]) { + double diff_rs_xor_random_loss1 = + (kMetricsXorRandom[code_index].average_residual_loss[k] - + kMetricsReedSolomon[code_index].average_residual_loss[k]) / + kMetricsXorRandom[code_index].average_residual_loss[k]; + double diff_rs_xor_random_loss2 = + (kMetricsXorRandom[code_index].average_residual_loss[k+1] - + kMetricsReedSolomon[code_index].average_residual_loss[k+1]) / + kMetricsXorRandom[code_index].average_residual_loss[k+1]; + EXPECT_GE(diff_rs_xor_random_loss1, scale * diff_rs_xor_random_loss2); + } + // TODO(marpan): Investigate the cases for the bursty mask where + // this trend is not strictly satisfied. + } + } + } +} + +// Verify the average residual loss behavior via the protection level and +// the code length. The average residual loss for a given (k1,m1) code +// should generally be higher than that of another code (k2,m2), which has +// either of the two conditions satisfied: +// 1) higher protection & code length at least as large: (k2+m2) >= (k1+m1), +// 2) equal protection and larger code length: (k2+m2) > (k1+m1). +// Currently does not hold for some cases of the XOR code with random mask. +TEST_F(FecPacketMaskMetricsTest, FecBehaviorViaProtectionLevelAndLength) { + SetLossModels(); + SetCodeParams(); + for (int code_index1 = 0; code_index1 < max_num_codes_; code_index1++) { + float protection_level1 = code_params_[code_index1].protection_level; + int length1 = code_params_[code_index1].num_media_packets + + code_params_[code_index1].num_fec_packets; + for (int code_index2 = 0; code_index2 < max_num_codes_; code_index2++) { + float protection_level2 = code_params_[code_index2].protection_level; + int length2 = code_params_[code_index2].num_media_packets + + code_params_[code_index2].num_fec_packets; + // Codes with higher protection are more efficient, conditioned on the + // length of the code (higher protection but shorter length codes are + // generally not more efficient). For two codes with equal protection, + // the longer code is generally more efficient. For high loss rate + // models, this condition may be violated for some codes with equal or + // very close protection levels. High loss rate case is excluded below. + if ((protection_level2 > protection_level1 && length2 >= length1) || + (protection_level2 == protection_level1 && length2 > length1)) { + for (int k = 0; k < kNumLossModels; k++) { + float loss_rate = loss_model_[k].average_loss_rate; + if (loss_rate < loss_rate_upper_threshold) { + EXPECT_LT( + kMetricsReedSolomon[code_index2].average_residual_loss[k], + kMetricsReedSolomon[code_index1].average_residual_loss[k]); + // TODO(marpan): There are some corner cases where this is not + // satisfied with the current packet masks. Look into updating + // these cases to see if this behavior should/can be satisfied, + // with overall lower residual loss for those XOR codes. + // EXPECT_LT( + // kMetricsXorBursty[code_index2].average_residual_loss[k], + // kMetricsXorBursty[code_index1].average_residual_loss[k]); + // EXPECT_LT( + // kMetricsXorRandom[code_index2].average_residual_loss[k], + // kMetricsXorRandom[code_index1].average_residual_loss[k]); + } + } + } + } + } +} + +// Verify the beheavior of the variance of the XOR codes. +// The partial recovery of the XOR versus the all or nothing behavior of the RS +// code means that the variance of the residual loss for XOR should generally +// not be worse than RS. +TEST_F(FecPacketMaskMetricsTest, FecVarianceBehaviorXorVsRs) { + SetLossModels(); + SetCodeParams(); + // The condition is not strictly satisfied with the current masks, + // i.e., for some codes, the variance of XOR may be slightly higher than RS. + // TODO(marpan): Examine this further to see if the condition can be strictly + // satisfied (i.e., scale = 1.0) for all codes with different/better masks. + double scale = 0.95; + for (int code_index = 0; code_index < max_num_codes_; code_index++) { + for (int k = 0; k < kNumLossModels; k++) { + EXPECT_LE(scale * + kMetricsXorRandom[code_index].variance_residual_loss[k], + kMetricsReedSolomon[code_index].variance_residual_loss[k]); + EXPECT_LE(scale * + kMetricsXorBursty[code_index].variance_residual_loss[k], + kMetricsReedSolomon[code_index].variance_residual_loss[k]); + } + } +} + +// For the bursty mask type, the residual loss must be strictly zero for all +// consecutive losses (i.e, gap = 0) with number of losses <= num_fec_packets. +// This is a design property of the bursty mask type. +TEST_F(FecPacketMaskMetricsTest, FecXorBurstyPerfectRecoveryConsecutiveLoss) { + SetLossModels(); + SetCodeParams(); + for (int code_index = 0; code_index < max_num_codes_; code_index++) { + int num_fec_packets = code_params_[code_index].num_fec_packets; + for (int loss = 1; loss <= num_fec_packets; loss++) { + int index = loss; // |gap| is zero. + EXPECT_EQ(kMetricsXorBursty[code_index]. + residual_loss_per_loss_gap[index], 0.0); + } + } +} + +// The XOR codes with random mask type are generally better than the ones with +// bursty mask type, for random loss models at low loss rates. +// The XOR codes with bursty mask types are generally better than the one with +// random mask type, for bursty loss models and/or high loss rates. +// TODO(marpan): Enable this test when some of the packet masks are updated. +// Some isolated cases of the codes don't pass this currently. +/* +TEST_F(FecPacketMaskMetricsTest, FecXorRandomVsBursty) { + SetLossModels(); + SetCodeParams(); + for (int code_index = 0; code_index < max_num_codes_; code_index++) { + double sum_residual_loss_random_mask_random_loss = 0.0; + double sum_residual_loss_bursty_mask_random_loss = 0.0; + double sum_residual_loss_random_mask_bursty_loss = 0.0; + double sum_residual_loss_bursty_mask_bursty_loss = 0.0; + // Compute the sum residual loss across the models, for each mask type. + for (int k = 0; k < kNumLossModels; k++) { + float loss_rate = loss_model_[k].average_loss_rate; + if (loss_model_[k].loss_type == kRandomLossModel && + loss_rate < loss_rate_upper_threshold) { + sum_residual_loss_random_mask_random_loss += + kMetricsXorRandom[code_index].average_residual_loss[k]; + sum_residual_loss_bursty_mask_random_loss += + kMetricsXorBursty[code_index].average_residual_loss[k]; + } else if (loss_model_[k].loss_type == kBurstyLossModel && + loss_rate > loss_rate_lower_threshold) { + sum_residual_loss_random_mask_bursty_loss += + kMetricsXorRandom[code_index].average_residual_loss[k]; + sum_residual_loss_bursty_mask_bursty_loss += + kMetricsXorBursty[code_index].average_residual_loss[k]; + } + } + EXPECT_LE(sum_residual_loss_random_mask_random_loss, + sum_residual_loss_bursty_mask_random_loss); + EXPECT_LE(sum_residual_loss_bursty_mask_bursty_loss, + sum_residual_loss_random_mask_bursty_loss); + } +} +*/ + +// Verify that the average recovery rate for each code is equal or above some +// threshold, for certain loss number conditions. +TEST_F(FecPacketMaskMetricsTest, FecRecoveryRateUnderLossConditions) { + SetLossModels(); + SetCodeParams(); + for (int code_index = 0; code_index < max_num_codes_; code_index++) { + int num_media_packets = code_params_[code_index].num_media_packets; + int num_fec_packets = code_params_[code_index].num_fec_packets; + // Perfect recovery (|recovery_rate_per_loss| == 1) is expected for + // |loss_number| = 1, for all codes. + int loss_number = 1; + EXPECT_EQ(kMetricsReedSolomon[code_index]. + recovery_rate_per_loss[loss_number], 1.0); + EXPECT_EQ(kMetricsXorRandom[code_index]. + recovery_rate_per_loss[loss_number], 1.0); + EXPECT_EQ(kMetricsXorBursty[code_index]. + recovery_rate_per_loss[loss_number], 1.0); + // For |loss_number| = |num_fec_packets| / 2, we expect the following: + // Perfect recovery for RS, and recovery for XOR above the threshold. + loss_number = num_fec_packets / 2 > 0 ? num_fec_packets / 2 : 1; + EXPECT_EQ(kMetricsReedSolomon[code_index]. + recovery_rate_per_loss[loss_number], 1.0); + EXPECT_GE(kMetricsXorRandom[code_index]. + recovery_rate_per_loss[loss_number], kRecoveryRateXorRandom[0]); + EXPECT_GE(kMetricsXorBursty[code_index]. + recovery_rate_per_loss[loss_number], kRecoveryRateXorBursty[0]); + // For |loss_number| = |num_fec_packets|, we expect the following: + // Perfect recovery for RS, and recovery for XOR above the threshold. + loss_number = num_fec_packets; + EXPECT_EQ(kMetricsReedSolomon[code_index]. + recovery_rate_per_loss[loss_number], 1.0); + EXPECT_GE(kMetricsXorRandom[code_index]. + recovery_rate_per_loss[loss_number], kRecoveryRateXorRandom[1]); + EXPECT_GE(kMetricsXorBursty[code_index]. + recovery_rate_per_loss[loss_number], kRecoveryRateXorBursty[1]); + // For |loss_number| = |num_fec_packets| + 1, we expect the following: + // Zero recovery for RS, but non-zero recovery for XOR. + if (num_fec_packets > 1 && num_media_packets > 2) { + loss_number = num_fec_packets + 1; + EXPECT_EQ(kMetricsReedSolomon[code_index]. + recovery_rate_per_loss[loss_number], 0.0); + EXPECT_GE(kMetricsXorRandom[code_index]. + recovery_rate_per_loss[loss_number], + kRecoveryRateXorRandom[2]); + EXPECT_GE(kMetricsXorBursty[code_index]. + recovery_rate_per_loss[loss_number], + kRecoveryRateXorBursty[2]); + } + } +} + +} // namespace webrtc |