summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/webrtc/modules/rtp_rtcp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/webrtc/modules/rtp_rtcp')
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/BUILD.gn422
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/DEPS6
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/OWNERS10
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_receiver.h69
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/flexfec_sender.h93
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/receive_statistics.h89
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h53
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_cvo.h56
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_extension_map.h80
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_header_parser.h45
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_packet_observer.h19
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h130
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_receiver.h115
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h466
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.cc26
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h508
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/include/ulpfec_receiver.h57
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h27
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h25
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h216
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_format_gn/moz.build260
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/rtp_rtcp_gn/moz.build265
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io.h408
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/byte_io_unittest.cc272
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.cc47
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/dtmf_queue.h41
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_bursty.h762
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_private_tables_random.h24524
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.cc217
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/fec_test_helper.h134
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc315
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer.h86
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc559
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver.cc156
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc583
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc170
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc323
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.cc779
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction.h419
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.cc433
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h108
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc290
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc137
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats.h57
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc197
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.cc66
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h81
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc69
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc496
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h134
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc370
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc83
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc144
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.cc31
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats.h40
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_nack_stats_unittest.cc64
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc86
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet.h103
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc97
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h60
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc110
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc137
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h59
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc147
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.cc89
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h51
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header_unittest.cc105
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc47
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h48
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc161
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc94
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h69
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc92
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc101
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h54
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc76
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc216
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h85
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc254
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.cc111
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.h62
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/fir_unittest.cc99
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc174
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h59
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc178
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc73
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h39
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc59
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc46
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h48
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc69
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h41
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request_unittest.cc66
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc110
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h60
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc161
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.cc141
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h60
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb_unittest.cc128
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc90
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h67
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc86
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc49
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h49
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc51
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc45
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h48
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc196
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h56
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc249
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc139
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h80
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc145
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc127
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h62
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate_unittest.cc96
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc71
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h51
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc110
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h56
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc108
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc112
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h55
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc96
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc645
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h106
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc470
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc107
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h53
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc93
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc42
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc1079
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h280
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc1280
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc1027
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender.h305
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc826
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.cc137
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver.h71
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.cc79
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_config.h77
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc292
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.h82
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc585
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_unittest.cc135
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_fec_unittest.cc1116
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.cc63
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format.h70
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.cc669
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h120
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc946
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.cc141
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h74
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc192
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.cc548
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h169
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc243
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h77
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc485
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.cc765
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h101
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc810
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map.cc151
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc114
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc424
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h198
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_header_parser.cc79
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.cc553
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet.h199
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc223
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h85
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc223
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.cc63
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h68
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h62
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc596
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc346
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc226
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc308
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h98
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc573
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h117
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.cc45
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h99
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc472
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc137
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h57
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h46
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc963
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h369
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc646
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.cc1412
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender.h344
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.cc339
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h98
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc2005
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc554
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h169
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.cc525
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility.h69
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc279
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.cc90
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util.h55
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/time_util_unittest.cc132
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.cc182
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/tmmbr_help.h33
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc244
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h110
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc170
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc131
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h67
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc244
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc260
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_impl.h57
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/ulpfec_receiver_unittest.cc485
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/source/video_codec_information.h27
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc163
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api.h72
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc299
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc252
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testAPI/test_api_video.cc183
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/average_residual_loss_xor_codes.h191
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_fec.cc478
-rw-r--r--third_party/libwebrtc/webrtc/modules/rtp_rtcp/test/testFec/test_packet_masks_metrics.cc1081
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(&params_, 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(&timestamp, &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(&timestamp, &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(&timestamp, &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